/**
 * GENERATED FILE, DO NOT EDIT
 *
 * SPDX-License-Identifier: MIT
 */

#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include "brei-shared.h"
#include "brei-proto.h"

#include "eis-proto.h"

/**
 * Forward declarations. This file is intended to be compile-able without including
 * any of the actual implementation files.
 */
struct eis_client;

/**
 * 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 eis_client_send_message(
  struct eis_client *eis_client, const struct brei_object *obj, uint32_t opcode,
  const char *signature, size_t nargs, ...
);

/***************************************************************************
 * Interface: eis_handshake                                                *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_handshake_interface *eis_handshake_get_interface(struct eis_handshake * eis_handshake);

/* returns the message sending context from the given struct */
struct eis_client * eis_handshake_get_client(struct eis_handshake * eis_handshake);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_handshake_get_proto_object(struct eis_handshake * eis_handshake);

/* request opcodes */
#define EIS_HANDSHAKE_REQUEST_HANDSHAKE_VERSION       0
#define EIS_HANDSHAKE_REQUEST_FINISH                  1
#define EIS_HANDSHAKE_REQUEST_CONTEXT_TYPE            2
#define EIS_HANDSHAKE_REQUEST_NAME                    3
#define EIS_HANDSHAKE_REQUEST_INTERFACE_VERSION       4

/* event opcodes */
#define EIS_HANDSHAKE_EVENT_HANDSHAKE_VERSION         0
#define EIS_HANDSHAKE_EVENT_INTERFACE_VERSION         1
#define EIS_HANDSHAKE_EVENT_CONNECTION                2

/* Message sender functions */
int
eis_handshake_event_handshake_version(struct eis_handshake * eis_handshake, uint32_t version)
{
	if (!eis_handshake)
		return -ENOENT;

	const struct brei_object *obj = eis_handshake_get_proto_object(eis_handshake);
	struct eis_client * ctx = eis_handshake_get_client(eis_handshake);

	if (obj->version < EIS_HANDSHAKE_EVENT_HANDSHAKE_VERSION_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_HANDSHAKE_EVENT_HANDSHAKE_VERSION, "u",
		1, version);
}

int
eis_handshake_event_interface_version(struct eis_handshake * eis_handshake, const char * name, uint32_t version)
{
	if (!eis_handshake)
		return -ENOENT;

	const struct brei_object *obj = eis_handshake_get_proto_object(eis_handshake);
	struct eis_client * ctx = eis_handshake_get_client(eis_handshake);

	if (obj->version < EIS_HANDSHAKE_EVENT_INTERFACE_VERSION_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_HANDSHAKE_EVENT_INTERFACE_VERSION, "su",
		2, name, version);
}

int
eis_handshake_event_connection(struct eis_handshake * eis_handshake, uint32_t serial, new_id_t connection, uint32_t version)
{
	if (!eis_handshake)
		return -ENOENT;

	const struct brei_object *obj = eis_handshake_get_proto_object(eis_handshake);
	struct eis_client * ctx = eis_handshake_get_client(eis_handshake);

	if (obj->version < EIS_HANDSHAKE_EVENT_CONNECTION_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_HANDSHAKE_EVENT_CONNECTION, "unu",
		3, serial, connection, version);
}


/**
 * The dispatcher for the eis_handshake interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_handshake_dispatcher(
	struct eis_handshake * eis_handshake,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_handshake_interface *interface = eis_handshake_get_interface(eis_handshake);
	const struct brei_object *obj = eis_handshake_get_proto_object(eis_handshake);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_HANDSHAKE_REQUEST_HANDSHAKE_VERSION:
		if (obj->version < EIS_HANDSHAKE_REQUEST_HANDSHAKE_VERSION_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->handshake_version != NULL);
		return interface->handshake_version(eis_handshake, (args + 0)->u);
	case EIS_HANDSHAKE_REQUEST_FINISH:
		if (obj->version < EIS_HANDSHAKE_REQUEST_FINISH_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->finish != NULL);
		return interface->finish(eis_handshake);
	case EIS_HANDSHAKE_REQUEST_CONTEXT_TYPE:
		if (obj->version < EIS_HANDSHAKE_REQUEST_CONTEXT_TYPE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->context_type != NULL);
		return interface->context_type(eis_handshake, (args + 0)->u);
	case EIS_HANDSHAKE_REQUEST_NAME:
		if (obj->version < EIS_HANDSHAKE_REQUEST_NAME_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->name != NULL);
		return interface->name(eis_handshake, (args + 0)->s);
	case EIS_HANDSHAKE_REQUEST_INTERFACE_VERSION:
		if (obj->version < EIS_HANDSHAKE_REQUEST_INTERFACE_VERSION_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->interface_version != NULL);
		return interface->interface_version(eis_handshake, (args + 0)->s, (args + 1)->u);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_handshake_requests[] = {
	{ "handshake_version", "u"  },
	{ "finish", ""  },
	{ "context_type", "u"  },
	{ "name", "s"  },
	{ "interface_version", "su"  },
};

static const struct brei_message eis_handshake_events[] = {
	{ "handshake_version", "u" },
	{ "interface_version", "su" },
	{ "connection", "unu" },
};

static const struct brei_message eis_handshake_incoming[] = {
	{ "handshake_version", "u" },
	{ "finish", "" },
	{ "context_type", "u" },
	{ "name", "s" },
	{ "interface_version", "su" },
};

const struct brei_interface eis_handshake_proto_interface = {
    .name = "eis_handshake", .version = 1,
    .nrequests = 5, .requests = eis_handshake_requests,
    .nevents = 3, .events = eis_handshake_events,
    .nincoming = 5, .incoming = eis_handshake_incoming,
    .dispatcher = (brei_event_dispatcher)eis_handshake_dispatcher,
};

/***************************************************************************
 * Interface: eis_connection                                               *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_connection_interface *eis_connection_get_interface(struct eis_connection * eis_connection);

/* returns the message sending context from the given struct */
struct eis_client * eis_connection_get_client(struct eis_connection * eis_connection);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_connection_get_proto_object(struct eis_connection * eis_connection);

/* request opcodes */
#define EIS_CONNECTION_REQUEST_SYNC                   0
#define EIS_CONNECTION_REQUEST_DISCONNECT             1

/* event opcodes */
#define EIS_CONNECTION_EVENT_DISCONNECTED             0
#define EIS_CONNECTION_EVENT_SEAT                     1
#define EIS_CONNECTION_EVENT_INVALID_OBJECT           2
#define EIS_CONNECTION_EVENT_PING                     3

/* Message sender functions */
int
eis_connection_event_disconnected(struct eis_connection * eis_connection, uint32_t last_serial, uint32_t reason, const char * explanation)
{
	if (!eis_connection)
		return -ENOENT;

	const struct brei_object *obj = eis_connection_get_proto_object(eis_connection);
	struct eis_client * ctx = eis_connection_get_client(eis_connection);

	if (obj->version < EIS_CONNECTION_EVENT_DISCONNECTED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_CONNECTION_EVENT_DISCONNECTED, "uus",
		3, last_serial, reason, explanation);
}

int
eis_connection_event_seat(struct eis_connection * eis_connection, new_id_t seat, uint32_t version)
{
	if (!eis_connection)
		return -ENOENT;

	const struct brei_object *obj = eis_connection_get_proto_object(eis_connection);
	struct eis_client * ctx = eis_connection_get_client(eis_connection);

	if (obj->version < EIS_CONNECTION_EVENT_SEAT_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_CONNECTION_EVENT_SEAT, "nu",
		2, seat, version);
}

int
eis_connection_event_invalid_object(struct eis_connection * eis_connection, uint32_t last_serial, uint64_t invalid_id)
{
	if (!eis_connection)
		return -ENOENT;

	const struct brei_object *obj = eis_connection_get_proto_object(eis_connection);
	struct eis_client * ctx = eis_connection_get_client(eis_connection);

	if (obj->version < EIS_CONNECTION_EVENT_INVALID_OBJECT_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_CONNECTION_EVENT_INVALID_OBJECT, "ut",
		2, last_serial, invalid_id);
}

int
eis_connection_event_ping(struct eis_connection * eis_connection, new_id_t ping, uint32_t version)
{
	if (!eis_connection)
		return -ENOENT;

	const struct brei_object *obj = eis_connection_get_proto_object(eis_connection);
	struct eis_client * ctx = eis_connection_get_client(eis_connection);

	if (obj->version < EIS_CONNECTION_EVENT_PING_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_CONNECTION_EVENT_PING, "nu",
		2, ping, version);
}


/**
 * The dispatcher for the eis_connection interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_connection_dispatcher(
	struct eis_connection * eis_connection,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_connection_interface *interface = eis_connection_get_interface(eis_connection);
	const struct brei_object *obj = eis_connection_get_proto_object(eis_connection);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_CONNECTION_REQUEST_SYNC:
		if (obj->version < EIS_CONNECTION_REQUEST_SYNC_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->sync != NULL);
		return interface->sync(eis_connection, (args + 0)->n, (args + 1)->u);
	case EIS_CONNECTION_REQUEST_DISCONNECT:
		if (obj->version < EIS_CONNECTION_REQUEST_DISCONNECT_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->disconnect != NULL);
		return interface->disconnect(eis_connection);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_connection_requests[] = {
	{ "sync", "nu"  },
	{ "disconnect", ""  },
};

static const struct brei_message eis_connection_events[] = {
	{ "disconnected", "uus" },
	{ "seat", "nu" },
	{ "invalid_object", "ut" },
	{ "ping", "nu" },
};

static const struct brei_message eis_connection_incoming[] = {
	{ "sync", "nu" },
	{ "disconnect", "" },
};

const struct brei_interface eis_connection_proto_interface = {
    .name = "eis_connection", .version = 1,
    .nrequests = 2, .requests = eis_connection_requests,
    .nevents = 4, .events = eis_connection_events,
    .nincoming = 2, .incoming = eis_connection_incoming,
    .dispatcher = (brei_event_dispatcher)eis_connection_dispatcher,
};

/***************************************************************************
 * Interface: eis_callback                                                 *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_callback_interface *eis_callback_get_interface(struct eis_callback * eis_callback);

/* returns the message sending context from the given struct */
struct eis_client * eis_callback_get_client(struct eis_callback * eis_callback);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_callback_get_proto_object(struct eis_callback * eis_callback);

/* request opcodes */

/* event opcodes */
#define EIS_CALLBACK_EVENT_DONE                       0

/* Message sender functions */
int
eis_callback_event_done(struct eis_callback * eis_callback, uint64_t callback_data)
{
	if (!eis_callback)
		return -ENOENT;

	const struct brei_object *obj = eis_callback_get_proto_object(eis_callback);
	struct eis_client * ctx = eis_callback_get_client(eis_callback);

	if (obj->version < EIS_CALLBACK_EVENT_DONE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_CALLBACK_EVENT_DONE, "t",
		1, callback_data);
}


/**
 * The dispatcher for the eis_callback interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_callback_dispatcher(
	struct eis_callback * eis_callback,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_callback_requests[] = {
};

static const struct brei_message eis_callback_events[] = {
	{ "done", "t" },
};

static const struct brei_message eis_callback_incoming[] = {
};

const struct brei_interface eis_callback_proto_interface = {
    .name = "eis_callback", .version = 1,
    .nrequests = 0, .requests = eis_callback_requests,
    .nevents = 1, .events = eis_callback_events,
    .nincoming = 0, .incoming = eis_callback_incoming,
    .dispatcher = (brei_event_dispatcher)eis_callback_dispatcher,
};

/***************************************************************************
 * Interface: eis_pingpong                                                 *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_pingpong_interface *eis_pingpong_get_interface(struct eis_pingpong * eis_pingpong);

/* returns the message sending context from the given struct */
struct eis_client * eis_pingpong_get_client(struct eis_pingpong * eis_pingpong);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_pingpong_get_proto_object(struct eis_pingpong * eis_pingpong);

/* request opcodes */
#define EIS_PINGPONG_REQUEST_DONE                     0

/* event opcodes */

/* Message sender functions */

/**
 * The dispatcher for the eis_pingpong interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_pingpong_dispatcher(
	struct eis_pingpong * eis_pingpong,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_pingpong_interface *interface = eis_pingpong_get_interface(eis_pingpong);
	const struct brei_object *obj = eis_pingpong_get_proto_object(eis_pingpong);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_PINGPONG_REQUEST_DONE:
		if (obj->version < EIS_PINGPONG_REQUEST_DONE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->done != NULL);
		return interface->done(eis_pingpong, (args + 0)->t);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_pingpong_requests[] = {
	{ "done", "t"  },
};

static const struct brei_message eis_pingpong_events[] = {
};

static const struct brei_message eis_pingpong_incoming[] = {
	{ "done", "t" },
};

const struct brei_interface eis_pingpong_proto_interface = {
    .name = "eis_pingpong", .version = 1,
    .nrequests = 1, .requests = eis_pingpong_requests,
    .nevents = 0, .events = eis_pingpong_events,
    .nincoming = 1, .incoming = eis_pingpong_incoming,
    .dispatcher = (brei_event_dispatcher)eis_pingpong_dispatcher,
};

/***************************************************************************
 * Interface: eis_seat                                                     *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_seat_interface *eis_seat_get_interface(struct eis_seat * eis_seat);

/* returns the message sending context from the given struct */
struct eis_client * eis_seat_get_client(struct eis_seat * eis_seat);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_seat_get_proto_object(struct eis_seat * eis_seat);

/* request opcodes */
#define EIS_SEAT_REQUEST_RELEASE                      0
#define EIS_SEAT_REQUEST_BIND                         1
#define EIS_SEAT_REQUEST_REQUEST_DEVICE               2

/* event opcodes */
#define EIS_SEAT_EVENT_DESTROYED                      0
#define EIS_SEAT_EVENT_NAME                           1
#define EIS_SEAT_EVENT_CAPABILITY                     2
#define EIS_SEAT_EVENT_DONE                           3
#define EIS_SEAT_EVENT_DEVICE                         4

/* Message sender functions */
int
eis_seat_event_destroyed(struct eis_seat * eis_seat, uint32_t serial)
{
	if (!eis_seat)
		return -ENOENT;

	const struct brei_object *obj = eis_seat_get_proto_object(eis_seat);
	struct eis_client * ctx = eis_seat_get_client(eis_seat);

	if (obj->version < EIS_SEAT_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SEAT_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_seat_event_name(struct eis_seat * eis_seat, const char * name)
{
	if (!eis_seat)
		return -ENOENT;

	const struct brei_object *obj = eis_seat_get_proto_object(eis_seat);
	struct eis_client * ctx = eis_seat_get_client(eis_seat);

	if (obj->version < EIS_SEAT_EVENT_NAME_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SEAT_EVENT_NAME, "s",
		1, name);
}

int
eis_seat_event_capability(struct eis_seat * eis_seat, uint64_t mask, const char * interface)
{
	if (!eis_seat)
		return -ENOENT;

	const struct brei_object *obj = eis_seat_get_proto_object(eis_seat);
	struct eis_client * ctx = eis_seat_get_client(eis_seat);

	if (obj->version < EIS_SEAT_EVENT_CAPABILITY_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SEAT_EVENT_CAPABILITY, "ts",
		2, mask, interface);
}

int
eis_seat_event_done(struct eis_seat * eis_seat)
{
	if (!eis_seat)
		return -ENOENT;

	const struct brei_object *obj = eis_seat_get_proto_object(eis_seat);
	struct eis_client * ctx = eis_seat_get_client(eis_seat);

	if (obj->version < EIS_SEAT_EVENT_DONE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SEAT_EVENT_DONE, "",
		0);
}

int
eis_seat_event_device(struct eis_seat * eis_seat, new_id_t device, uint32_t version)
{
	if (!eis_seat)
		return -ENOENT;

	const struct brei_object *obj = eis_seat_get_proto_object(eis_seat);
	struct eis_client * ctx = eis_seat_get_client(eis_seat);

	if (obj->version < EIS_SEAT_EVENT_DEVICE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SEAT_EVENT_DEVICE, "nu",
		2, device, version);
}


/**
 * The dispatcher for the eis_seat interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_seat_dispatcher(
	struct eis_seat * eis_seat,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_seat_interface *interface = eis_seat_get_interface(eis_seat);
	const struct brei_object *obj = eis_seat_get_proto_object(eis_seat);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_SEAT_REQUEST_RELEASE:
		if (obj->version < EIS_SEAT_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_seat);
	case EIS_SEAT_REQUEST_BIND:
		if (obj->version < EIS_SEAT_REQUEST_BIND_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->bind != NULL);
		return interface->bind(eis_seat, (args + 0)->t);
	case EIS_SEAT_REQUEST_REQUEST_DEVICE:
		if (obj->version < EIS_SEAT_REQUEST_REQUEST_DEVICE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->request_device != NULL);
		return interface->request_device(eis_seat, (args + 0)->t);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_seat_requests[] = {
	{ "release", ""  },
	{ "bind", "t"  },
	{ "request_device", "t"  },
};

static const struct brei_message eis_seat_events[] = {
	{ "destroyed", "u" },
	{ "name", "s" },
	{ "capability", "ts" },
	{ "done", "" },
	{ "device", "nu" },
};

static const struct brei_message eis_seat_incoming[] = {
	{ "release", "" },
	{ "bind", "t" },
	{ "request_device", "t" },
};

const struct brei_interface eis_seat_proto_interface = {
    .name = "eis_seat", .version = 2,
    .nrequests = 3, .requests = eis_seat_requests,
    .nevents = 5, .events = eis_seat_events,
    .nincoming = 3, .incoming = eis_seat_incoming,
    .dispatcher = (brei_event_dispatcher)eis_seat_dispatcher,
};

/***************************************************************************
 * Interface: eis_device                                                   *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_device_interface *eis_device_get_interface(struct eis_device * eis_device);

/* returns the message sending context from the given struct */
struct eis_client * eis_device_get_client(struct eis_device * eis_device);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_device_get_proto_object(struct eis_device * eis_device);

/* request opcodes */
#define EIS_DEVICE_REQUEST_RELEASE                    0
#define EIS_DEVICE_REQUEST_START_EMULATING            1
#define EIS_DEVICE_REQUEST_STOP_EMULATING             2
#define EIS_DEVICE_REQUEST_FRAME                      3
#define EIS_DEVICE_REQUEST_READY                      4

/* event opcodes */
#define EIS_DEVICE_EVENT_DESTROYED                    0
#define EIS_DEVICE_EVENT_NAME                         1
#define EIS_DEVICE_EVENT_DEVICE_TYPE                  2
#define EIS_DEVICE_EVENT_DIMENSIONS                   3
#define EIS_DEVICE_EVENT_REGION                       4
#define EIS_DEVICE_EVENT_INTERFACE                    5
#define EIS_DEVICE_EVENT_DONE                         6
#define EIS_DEVICE_EVENT_RESUMED                      7
#define EIS_DEVICE_EVENT_PAUSED                       8
#define EIS_DEVICE_EVENT_START_EMULATING              9
#define EIS_DEVICE_EVENT_STOP_EMULATING               10
#define EIS_DEVICE_EVENT_FRAME                        11
#define EIS_DEVICE_EVENT_REGION_MAPPING_ID            12

/* Message sender functions */
int
eis_device_event_destroyed(struct eis_device * eis_device, uint32_t serial)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_device_event_name(struct eis_device * eis_device, const char * name)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_NAME_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_NAME, "s",
		1, name);
}

int
eis_device_event_device_type(struct eis_device * eis_device, uint32_t device_type)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_DEVICE_TYPE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_DEVICE_TYPE, "u",
		1, device_type);
}

int
eis_device_event_dimensions(struct eis_device * eis_device, uint32_t width, uint32_t height)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_DIMENSIONS_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_DIMENSIONS, "uu",
		2, width, height);
}

int
eis_device_event_region(struct eis_device * eis_device, uint32_t offset_x, uint32_t offset_y, uint32_t width, uint32_t hight, float scale)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_REGION_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_REGION, "uuuuf",
		5, offset_x, offset_y, width, hight, scale);
}

int
eis_device_event_interface(struct eis_device * eis_device, new_id_t object, const char * interface_name, uint32_t version)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_INTERFACE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_INTERFACE, "nsu",
		3, object, interface_name, version);
}

int
eis_device_event_done(struct eis_device * eis_device)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_DONE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_DONE, "",
		0);
}

int
eis_device_event_resumed(struct eis_device * eis_device, uint32_t serial)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_RESUMED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_RESUMED, "u",
		1, serial);
}

int
eis_device_event_paused(struct eis_device * eis_device, uint32_t serial)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_PAUSED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_PAUSED, "u",
		1, serial);
}

int
eis_device_event_start_emulating(struct eis_device * eis_device, uint32_t serial, uint32_t sequence)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_START_EMULATING_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_START_EMULATING, "uu",
		2, serial, sequence);
}

int
eis_device_event_stop_emulating(struct eis_device * eis_device, uint32_t serial)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_STOP_EMULATING_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_STOP_EMULATING, "u",
		1, serial);
}

int
eis_device_event_frame(struct eis_device * eis_device, uint32_t serial, uint64_t timestamp)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_FRAME_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_FRAME, "ut",
		2, serial, timestamp);
}

int
eis_device_event_region_mapping_id(struct eis_device * eis_device, const char * mapping_id)
{
	if (!eis_device)
		return -ENOENT;

	const struct brei_object *obj = eis_device_get_proto_object(eis_device);
	struct eis_client * ctx = eis_device_get_client(eis_device);

	if (obj->version < EIS_DEVICE_EVENT_REGION_MAPPING_ID_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_DEVICE_EVENT_REGION_MAPPING_ID, "s",
		1, mapping_id);
}


/**
 * The dispatcher for the eis_device interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_device_dispatcher(
	struct eis_device * eis_device,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_device_interface *interface = eis_device_get_interface(eis_device);
	const struct brei_object *obj = eis_device_get_proto_object(eis_device);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_DEVICE_REQUEST_RELEASE:
		if (obj->version < EIS_DEVICE_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_device);
	case EIS_DEVICE_REQUEST_START_EMULATING:
		if (obj->version < EIS_DEVICE_REQUEST_START_EMULATING_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->start_emulating != NULL);
		return interface->start_emulating(eis_device, (args + 0)->u, (args + 1)->u);
	case EIS_DEVICE_REQUEST_STOP_EMULATING:
		if (obj->version < EIS_DEVICE_REQUEST_STOP_EMULATING_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->stop_emulating != NULL);
		return interface->stop_emulating(eis_device, (args + 0)->u);
	case EIS_DEVICE_REQUEST_FRAME:
		if (obj->version < EIS_DEVICE_REQUEST_FRAME_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->frame != NULL);
		return interface->frame(eis_device, (args + 0)->u, (args + 1)->t);
	case EIS_DEVICE_REQUEST_READY:
		if (obj->version < EIS_DEVICE_REQUEST_READY_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->ready != NULL);
		return interface->ready(eis_device);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_device_requests[] = {
	{ "release", ""  },
	{ "start_emulating", "uu"  },
	{ "stop_emulating", "u"  },
	{ "frame", "ut"  },
	{ "ready", ""  },
};

static const struct brei_message eis_device_events[] = {
	{ "destroyed", "u" },
	{ "name", "s" },
	{ "device_type", "u" },
	{ "dimensions", "uu" },
	{ "region", "uuuuf" },
	{ "interface", "nsu" },
	{ "done", "" },
	{ "resumed", "u" },
	{ "paused", "u" },
	{ "start_emulating", "uu" },
	{ "stop_emulating", "u" },
	{ "frame", "ut" },
	{ "region_mapping_id", "s" },
};

static const struct brei_message eis_device_incoming[] = {
	{ "release", "" },
	{ "start_emulating", "uu" },
	{ "stop_emulating", "u" },
	{ "frame", "ut" },
	{ "ready", "" },
};

const struct brei_interface eis_device_proto_interface = {
    .name = "eis_device", .version = 3,
    .nrequests = 5, .requests = eis_device_requests,
    .nevents = 13, .events = eis_device_events,
    .nincoming = 5, .incoming = eis_device_incoming,
    .dispatcher = (brei_event_dispatcher)eis_device_dispatcher,
};

/***************************************************************************
 * Interface: eis_pointer                                                  *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_pointer_interface *eis_pointer_get_interface(struct eis_pointer * eis_pointer);

/* returns the message sending context from the given struct */
struct eis_client * eis_pointer_get_client(struct eis_pointer * eis_pointer);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_pointer_get_proto_object(struct eis_pointer * eis_pointer);

/* request opcodes */
#define EIS_POINTER_REQUEST_RELEASE                   0
#define EIS_POINTER_REQUEST_MOTION_RELATIVE           1

/* event opcodes */
#define EIS_POINTER_EVENT_DESTROYED                   0
#define EIS_POINTER_EVENT_MOTION_RELATIVE             1

/* Message sender functions */
int
eis_pointer_event_destroyed(struct eis_pointer * eis_pointer, uint32_t serial)
{
	if (!eis_pointer)
		return -ENOENT;

	const struct brei_object *obj = eis_pointer_get_proto_object(eis_pointer);
	struct eis_client * ctx = eis_pointer_get_client(eis_pointer);

	if (obj->version < EIS_POINTER_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_POINTER_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_pointer_event_motion_relative(struct eis_pointer * eis_pointer, float x, float y)
{
	if (!eis_pointer)
		return -ENOENT;

	const struct brei_object *obj = eis_pointer_get_proto_object(eis_pointer);
	struct eis_client * ctx = eis_pointer_get_client(eis_pointer);

	if (obj->version < EIS_POINTER_EVENT_MOTION_RELATIVE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_POINTER_EVENT_MOTION_RELATIVE, "ff",
		2, x, y);
}


/**
 * The dispatcher for the eis_pointer interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_pointer_dispatcher(
	struct eis_pointer * eis_pointer,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_pointer_interface *interface = eis_pointer_get_interface(eis_pointer);
	const struct brei_object *obj = eis_pointer_get_proto_object(eis_pointer);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_POINTER_REQUEST_RELEASE:
		if (obj->version < EIS_POINTER_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_pointer);
	case EIS_POINTER_REQUEST_MOTION_RELATIVE:
		if (obj->version < EIS_POINTER_REQUEST_MOTION_RELATIVE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->motion_relative != NULL);
		return interface->motion_relative(eis_pointer, (args + 0)->f, (args + 1)->f);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_pointer_requests[] = {
	{ "release", ""  },
	{ "motion_relative", "ff"  },
};

static const struct brei_message eis_pointer_events[] = {
	{ "destroyed", "u" },
	{ "motion_relative", "ff" },
};

static const struct brei_message eis_pointer_incoming[] = {
	{ "release", "" },
	{ "motion_relative", "ff" },
};

const struct brei_interface eis_pointer_proto_interface = {
    .name = "eis_pointer", .version = 1,
    .nrequests = 2, .requests = eis_pointer_requests,
    .nevents = 2, .events = eis_pointer_events,
    .nincoming = 2, .incoming = eis_pointer_incoming,
    .dispatcher = (brei_event_dispatcher)eis_pointer_dispatcher,
};

/***************************************************************************
 * Interface: eis_pointer_absolute                                         *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_pointer_absolute_interface *eis_pointer_absolute_get_interface(struct eis_pointer_absolute * eis_pointer_absolute);

/* returns the message sending context from the given struct */
struct eis_client * eis_pointer_absolute_get_client(struct eis_pointer_absolute * eis_pointer_absolute);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_pointer_absolute_get_proto_object(struct eis_pointer_absolute * eis_pointer_absolute);

/* request opcodes */
#define EIS_POINTER_ABSOLUTE_REQUEST_RELEASE          0
#define EIS_POINTER_ABSOLUTE_REQUEST_MOTION_ABSOLUTE  1

/* event opcodes */
#define EIS_POINTER_ABSOLUTE_EVENT_DESTROYED          0
#define EIS_POINTER_ABSOLUTE_EVENT_MOTION_ABSOLUTE    1

/* Message sender functions */
int
eis_pointer_absolute_event_destroyed(struct eis_pointer_absolute * eis_pointer_absolute, uint32_t serial)
{
	if (!eis_pointer_absolute)
		return -ENOENT;

	const struct brei_object *obj = eis_pointer_absolute_get_proto_object(eis_pointer_absolute);
	struct eis_client * ctx = eis_pointer_absolute_get_client(eis_pointer_absolute);

	if (obj->version < EIS_POINTER_ABSOLUTE_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_POINTER_ABSOLUTE_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_pointer_absolute_event_motion_absolute(struct eis_pointer_absolute * eis_pointer_absolute, float x, float y)
{
	if (!eis_pointer_absolute)
		return -ENOENT;

	const struct brei_object *obj = eis_pointer_absolute_get_proto_object(eis_pointer_absolute);
	struct eis_client * ctx = eis_pointer_absolute_get_client(eis_pointer_absolute);

	if (obj->version < EIS_POINTER_ABSOLUTE_EVENT_MOTION_ABSOLUTE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_POINTER_ABSOLUTE_EVENT_MOTION_ABSOLUTE, "ff",
		2, x, y);
}


/**
 * The dispatcher for the eis_pointer_absolute interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_pointer_absolute_dispatcher(
	struct eis_pointer_absolute * eis_pointer_absolute,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_pointer_absolute_interface *interface = eis_pointer_absolute_get_interface(eis_pointer_absolute);
	const struct brei_object *obj = eis_pointer_absolute_get_proto_object(eis_pointer_absolute);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_POINTER_ABSOLUTE_REQUEST_RELEASE:
		if (obj->version < EIS_POINTER_ABSOLUTE_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_pointer_absolute);
	case EIS_POINTER_ABSOLUTE_REQUEST_MOTION_ABSOLUTE:
		if (obj->version < EIS_POINTER_ABSOLUTE_REQUEST_MOTION_ABSOLUTE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->motion_absolute != NULL);
		return interface->motion_absolute(eis_pointer_absolute, (args + 0)->f, (args + 1)->f);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_pointer_absolute_requests[] = {
	{ "release", ""  },
	{ "motion_absolute", "ff"  },
};

static const struct brei_message eis_pointer_absolute_events[] = {
	{ "destroyed", "u" },
	{ "motion_absolute", "ff" },
};

static const struct brei_message eis_pointer_absolute_incoming[] = {
	{ "release", "" },
	{ "motion_absolute", "ff" },
};

const struct brei_interface eis_pointer_absolute_proto_interface = {
    .name = "eis_pointer_absolute", .version = 1,
    .nrequests = 2, .requests = eis_pointer_absolute_requests,
    .nevents = 2, .events = eis_pointer_absolute_events,
    .nincoming = 2, .incoming = eis_pointer_absolute_incoming,
    .dispatcher = (brei_event_dispatcher)eis_pointer_absolute_dispatcher,
};

/***************************************************************************
 * Interface: eis_scroll                                                   *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_scroll_interface *eis_scroll_get_interface(struct eis_scroll * eis_scroll);

/* returns the message sending context from the given struct */
struct eis_client * eis_scroll_get_client(struct eis_scroll * eis_scroll);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_scroll_get_proto_object(struct eis_scroll * eis_scroll);

/* request opcodes */
#define EIS_SCROLL_REQUEST_RELEASE                    0
#define EIS_SCROLL_REQUEST_SCROLL                     1
#define EIS_SCROLL_REQUEST_SCROLL_DISCRETE            2
#define EIS_SCROLL_REQUEST_SCROLL_STOP                3

/* event opcodes */
#define EIS_SCROLL_EVENT_DESTROYED                    0
#define EIS_SCROLL_EVENT_SCROLL                       1
#define EIS_SCROLL_EVENT_SCROLL_DISCRETE              2
#define EIS_SCROLL_EVENT_SCROLL_STOP                  3

/* Message sender functions */
int
eis_scroll_event_destroyed(struct eis_scroll * eis_scroll, uint32_t serial)
{
	if (!eis_scroll)
		return -ENOENT;

	const struct brei_object *obj = eis_scroll_get_proto_object(eis_scroll);
	struct eis_client * ctx = eis_scroll_get_client(eis_scroll);

	if (obj->version < EIS_SCROLL_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SCROLL_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_scroll_event_scroll(struct eis_scroll * eis_scroll, float x, float y)
{
	if (!eis_scroll)
		return -ENOENT;

	const struct brei_object *obj = eis_scroll_get_proto_object(eis_scroll);
	struct eis_client * ctx = eis_scroll_get_client(eis_scroll);

	if (obj->version < EIS_SCROLL_EVENT_SCROLL_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SCROLL_EVENT_SCROLL, "ff",
		2, x, y);
}

int
eis_scroll_event_scroll_discrete(struct eis_scroll * eis_scroll, int32_t x, int32_t y)
{
	if (!eis_scroll)
		return -ENOENT;

	const struct brei_object *obj = eis_scroll_get_proto_object(eis_scroll);
	struct eis_client * ctx = eis_scroll_get_client(eis_scroll);

	if (obj->version < EIS_SCROLL_EVENT_SCROLL_DISCRETE_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SCROLL_EVENT_SCROLL_DISCRETE, "ii",
		2, x, y);
}

int
eis_scroll_event_scroll_stop(struct eis_scroll * eis_scroll, uint32_t x, uint32_t y, uint32_t is_cancel)
{
	if (!eis_scroll)
		return -ENOENT;

	const struct brei_object *obj = eis_scroll_get_proto_object(eis_scroll);
	struct eis_client * ctx = eis_scroll_get_client(eis_scroll);

	if (obj->version < EIS_SCROLL_EVENT_SCROLL_STOP_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_SCROLL_EVENT_SCROLL_STOP, "uuu",
		3, x, y, is_cancel);
}


/**
 * The dispatcher for the eis_scroll interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_scroll_dispatcher(
	struct eis_scroll * eis_scroll,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_scroll_interface *interface = eis_scroll_get_interface(eis_scroll);
	const struct brei_object *obj = eis_scroll_get_proto_object(eis_scroll);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_SCROLL_REQUEST_RELEASE:
		if (obj->version < EIS_SCROLL_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_scroll);
	case EIS_SCROLL_REQUEST_SCROLL:
		if (obj->version < EIS_SCROLL_REQUEST_SCROLL_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->scroll != NULL);
		return interface->scroll(eis_scroll, (args + 0)->f, (args + 1)->f);
	case EIS_SCROLL_REQUEST_SCROLL_DISCRETE:
		if (obj->version < EIS_SCROLL_REQUEST_SCROLL_DISCRETE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->scroll_discrete != NULL);
		return interface->scroll_discrete(eis_scroll, (args + 0)->i, (args + 1)->i);
	case EIS_SCROLL_REQUEST_SCROLL_STOP:
		if (obj->version < EIS_SCROLL_REQUEST_SCROLL_STOP_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->scroll_stop != NULL);
		return interface->scroll_stop(eis_scroll, (args + 0)->u, (args + 1)->u, (args + 2)->u);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_scroll_requests[] = {
	{ "release", ""  },
	{ "scroll", "ff"  },
	{ "scroll_discrete", "ii"  },
	{ "scroll_stop", "uuu"  },
};

static const struct brei_message eis_scroll_events[] = {
	{ "destroyed", "u" },
	{ "scroll", "ff" },
	{ "scroll_discrete", "ii" },
	{ "scroll_stop", "uuu" },
};

static const struct brei_message eis_scroll_incoming[] = {
	{ "release", "" },
	{ "scroll", "ff" },
	{ "scroll_discrete", "ii" },
	{ "scroll_stop", "uuu" },
};

const struct brei_interface eis_scroll_proto_interface = {
    .name = "eis_scroll", .version = 1,
    .nrequests = 4, .requests = eis_scroll_requests,
    .nevents = 4, .events = eis_scroll_events,
    .nincoming = 4, .incoming = eis_scroll_incoming,
    .dispatcher = (brei_event_dispatcher)eis_scroll_dispatcher,
};

/***************************************************************************
 * Interface: eis_button                                                   *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_button_interface *eis_button_get_interface(struct eis_button * eis_button);

/* returns the message sending context from the given struct */
struct eis_client * eis_button_get_client(struct eis_button * eis_button);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_button_get_proto_object(struct eis_button * eis_button);

/* request opcodes */
#define EIS_BUTTON_REQUEST_RELEASE                    0
#define EIS_BUTTON_REQUEST_BUTTON                     1

/* event opcodes */
#define EIS_BUTTON_EVENT_DESTROYED                    0
#define EIS_BUTTON_EVENT_BUTTON                       1

/* Message sender functions */
int
eis_button_event_destroyed(struct eis_button * eis_button, uint32_t serial)
{
	if (!eis_button)
		return -ENOENT;

	const struct brei_object *obj = eis_button_get_proto_object(eis_button);
	struct eis_client * ctx = eis_button_get_client(eis_button);

	if (obj->version < EIS_BUTTON_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_BUTTON_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_button_event_button(struct eis_button * eis_button, uint32_t button, uint32_t state)
{
	if (!eis_button)
		return -ENOENT;

	const struct brei_object *obj = eis_button_get_proto_object(eis_button);
	struct eis_client * ctx = eis_button_get_client(eis_button);

	if (obj->version < EIS_BUTTON_EVENT_BUTTON_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_BUTTON_EVENT_BUTTON, "uu",
		2, button, state);
}


/**
 * The dispatcher for the eis_button interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_button_dispatcher(
	struct eis_button * eis_button,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_button_interface *interface = eis_button_get_interface(eis_button);
	const struct brei_object *obj = eis_button_get_proto_object(eis_button);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_BUTTON_REQUEST_RELEASE:
		if (obj->version < EIS_BUTTON_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_button);
	case EIS_BUTTON_REQUEST_BUTTON:
		if (obj->version < EIS_BUTTON_REQUEST_BUTTON_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->button != NULL);
		return interface->button(eis_button, (args + 0)->u, (args + 1)->u);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_button_requests[] = {
	{ "release", ""  },
	{ "button", "uu"  },
};

static const struct brei_message eis_button_events[] = {
	{ "destroyed", "u" },
	{ "button", "uu" },
};

static const struct brei_message eis_button_incoming[] = {
	{ "release", "" },
	{ "button", "uu" },
};

const struct brei_interface eis_button_proto_interface = {
    .name = "eis_button", .version = 1,
    .nrequests = 2, .requests = eis_button_requests,
    .nevents = 2, .events = eis_button_events,
    .nincoming = 2, .incoming = eis_button_incoming,
    .dispatcher = (brei_event_dispatcher)eis_button_dispatcher,
};

/***************************************************************************
 * Interface: eis_keyboard                                                 *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_keyboard_interface *eis_keyboard_get_interface(struct eis_keyboard * eis_keyboard);

/* returns the message sending context from the given struct */
struct eis_client * eis_keyboard_get_client(struct eis_keyboard * eis_keyboard);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_keyboard_get_proto_object(struct eis_keyboard * eis_keyboard);

/* request opcodes */
#define EIS_KEYBOARD_REQUEST_RELEASE                  0
#define EIS_KEYBOARD_REQUEST_KEY                      1

/* event opcodes */
#define EIS_KEYBOARD_EVENT_DESTROYED                  0
#define EIS_KEYBOARD_EVENT_KEYMAP                     1
#define EIS_KEYBOARD_EVENT_KEY                        2
#define EIS_KEYBOARD_EVENT_MODIFIERS                  3

/* Message sender functions */
int
eis_keyboard_event_destroyed(struct eis_keyboard * eis_keyboard, uint32_t serial)
{
	if (!eis_keyboard)
		return -ENOENT;

	const struct brei_object *obj = eis_keyboard_get_proto_object(eis_keyboard);
	struct eis_client * ctx = eis_keyboard_get_client(eis_keyboard);

	if (obj->version < EIS_KEYBOARD_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_KEYBOARD_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_keyboard_event_keymap(struct eis_keyboard * eis_keyboard, uint32_t keymap_type, uint32_t size, int keymap)
{
	if (!eis_keyboard)
		return -ENOENT;

	const struct brei_object *obj = eis_keyboard_get_proto_object(eis_keyboard);
	struct eis_client * ctx = eis_keyboard_get_client(eis_keyboard);

	if (obj->version < EIS_KEYBOARD_EVENT_KEYMAP_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_KEYBOARD_EVENT_KEYMAP, "uuh",
		3, keymap_type, size, keymap);
}

int
eis_keyboard_event_key(struct eis_keyboard * eis_keyboard, uint32_t key, uint32_t state)
{
	if (!eis_keyboard)
		return -ENOENT;

	const struct brei_object *obj = eis_keyboard_get_proto_object(eis_keyboard);
	struct eis_client * ctx = eis_keyboard_get_client(eis_keyboard);

	if (obj->version < EIS_KEYBOARD_EVENT_KEY_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_KEYBOARD_EVENT_KEY, "uu",
		2, key, state);
}

int
eis_keyboard_event_modifiers(struct eis_keyboard * eis_keyboard, uint32_t serial, uint32_t depressed, uint32_t locked, uint32_t latched, uint32_t group)
{
	if (!eis_keyboard)
		return -ENOENT;

	const struct brei_object *obj = eis_keyboard_get_proto_object(eis_keyboard);
	struct eis_client * ctx = eis_keyboard_get_client(eis_keyboard);

	if (obj->version < EIS_KEYBOARD_EVENT_MODIFIERS_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_KEYBOARD_EVENT_MODIFIERS, "uuuuu",
		5, serial, depressed, locked, latched, group);
}


/**
 * The dispatcher for the eis_keyboard interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_keyboard_dispatcher(
	struct eis_keyboard * eis_keyboard,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_keyboard_interface *interface = eis_keyboard_get_interface(eis_keyboard);
	const struct brei_object *obj = eis_keyboard_get_proto_object(eis_keyboard);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_KEYBOARD_REQUEST_RELEASE:
		if (obj->version < EIS_KEYBOARD_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_keyboard);
	case EIS_KEYBOARD_REQUEST_KEY:
		if (obj->version < EIS_KEYBOARD_REQUEST_KEY_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->key != NULL);
		return interface->key(eis_keyboard, (args + 0)->u, (args + 1)->u);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_keyboard_requests[] = {
	{ "release", ""  },
	{ "key", "uu"  },
};

static const struct brei_message eis_keyboard_events[] = {
	{ "destroyed", "u" },
	{ "keymap", "uuh" },
	{ "key", "uu" },
	{ "modifiers", "uuuuu" },
};

static const struct brei_message eis_keyboard_incoming[] = {
	{ "release", "" },
	{ "key", "uu" },
};

const struct brei_interface eis_keyboard_proto_interface = {
    .name = "eis_keyboard", .version = 1,
    .nrequests = 2, .requests = eis_keyboard_requests,
    .nevents = 4, .events = eis_keyboard_events,
    .nincoming = 2, .incoming = eis_keyboard_incoming,
    .dispatcher = (brei_event_dispatcher)eis_keyboard_dispatcher,
};

/***************************************************************************
 * Interface: eis_touchscreen                                              *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_touchscreen_interface *eis_touchscreen_get_interface(struct eis_touchscreen * eis_touchscreen);

/* returns the message sending context from the given struct */
struct eis_client * eis_touchscreen_get_client(struct eis_touchscreen * eis_touchscreen);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_touchscreen_get_proto_object(struct eis_touchscreen * eis_touchscreen);

/* request opcodes */
#define EIS_TOUCHSCREEN_REQUEST_RELEASE               0
#define EIS_TOUCHSCREEN_REQUEST_DOWN                  1
#define EIS_TOUCHSCREEN_REQUEST_MOTION                2
#define EIS_TOUCHSCREEN_REQUEST_UP                    3
#define EIS_TOUCHSCREEN_REQUEST_CANCEL                4

/* event opcodes */
#define EIS_TOUCHSCREEN_EVENT_DESTROYED               0
#define EIS_TOUCHSCREEN_EVENT_DOWN                    1
#define EIS_TOUCHSCREEN_EVENT_MOTION                  2
#define EIS_TOUCHSCREEN_EVENT_UP                      3
#define EIS_TOUCHSCREEN_EVENT_CANCEL                  4

/* Message sender functions */
int
eis_touchscreen_event_destroyed(struct eis_touchscreen * eis_touchscreen, uint32_t serial)
{
	if (!eis_touchscreen)
		return -ENOENT;

	const struct brei_object *obj = eis_touchscreen_get_proto_object(eis_touchscreen);
	struct eis_client * ctx = eis_touchscreen_get_client(eis_touchscreen);

	if (obj->version < EIS_TOUCHSCREEN_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TOUCHSCREEN_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_touchscreen_event_down(struct eis_touchscreen * eis_touchscreen, uint32_t touchid, float x, float y)
{
	if (!eis_touchscreen)
		return -ENOENT;

	const struct brei_object *obj = eis_touchscreen_get_proto_object(eis_touchscreen);
	struct eis_client * ctx = eis_touchscreen_get_client(eis_touchscreen);

	if (obj->version < EIS_TOUCHSCREEN_EVENT_DOWN_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TOUCHSCREEN_EVENT_DOWN, "uff",
		3, touchid, x, y);
}

int
eis_touchscreen_event_motion(struct eis_touchscreen * eis_touchscreen, uint32_t touchid, float x, float y)
{
	if (!eis_touchscreen)
		return -ENOENT;

	const struct brei_object *obj = eis_touchscreen_get_proto_object(eis_touchscreen);
	struct eis_client * ctx = eis_touchscreen_get_client(eis_touchscreen);

	if (obj->version < EIS_TOUCHSCREEN_EVENT_MOTION_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TOUCHSCREEN_EVENT_MOTION, "uff",
		3, touchid, x, y);
}

int
eis_touchscreen_event_up(struct eis_touchscreen * eis_touchscreen, uint32_t touchid)
{
	if (!eis_touchscreen)
		return -ENOENT;

	const struct brei_object *obj = eis_touchscreen_get_proto_object(eis_touchscreen);
	struct eis_client * ctx = eis_touchscreen_get_client(eis_touchscreen);

	if (obj->version < EIS_TOUCHSCREEN_EVENT_UP_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TOUCHSCREEN_EVENT_UP, "u",
		1, touchid);
}

int
eis_touchscreen_event_cancel(struct eis_touchscreen * eis_touchscreen, uint32_t touchid)
{
	if (!eis_touchscreen)
		return -ENOENT;

	const struct brei_object *obj = eis_touchscreen_get_proto_object(eis_touchscreen);
	struct eis_client * ctx = eis_touchscreen_get_client(eis_touchscreen);

	if (obj->version < EIS_TOUCHSCREEN_EVENT_CANCEL_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TOUCHSCREEN_EVENT_CANCEL, "u",
		1, touchid);
}


/**
 * The dispatcher for the eis_touchscreen interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_touchscreen_dispatcher(
	struct eis_touchscreen * eis_touchscreen,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_touchscreen_interface *interface = eis_touchscreen_get_interface(eis_touchscreen);
	const struct brei_object *obj = eis_touchscreen_get_proto_object(eis_touchscreen);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_TOUCHSCREEN_REQUEST_RELEASE:
		if (obj->version < EIS_TOUCHSCREEN_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_touchscreen);
	case EIS_TOUCHSCREEN_REQUEST_DOWN:
		if (obj->version < EIS_TOUCHSCREEN_REQUEST_DOWN_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->down != NULL);
		return interface->down(eis_touchscreen, (args + 0)->u, (args + 1)->f, (args + 2)->f);
	case EIS_TOUCHSCREEN_REQUEST_MOTION:
		if (obj->version < EIS_TOUCHSCREEN_REQUEST_MOTION_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->motion != NULL);
		return interface->motion(eis_touchscreen, (args + 0)->u, (args + 1)->f, (args + 2)->f);
	case EIS_TOUCHSCREEN_REQUEST_UP:
		if (obj->version < EIS_TOUCHSCREEN_REQUEST_UP_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->up != NULL);
		return interface->up(eis_touchscreen, (args + 0)->u);
	case EIS_TOUCHSCREEN_REQUEST_CANCEL:
		if (obj->version < EIS_TOUCHSCREEN_REQUEST_CANCEL_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->cancel != NULL);
		return interface->cancel(eis_touchscreen, (args + 0)->u);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_touchscreen_requests[] = {
	{ "release", ""  },
	{ "down", "uff"  },
	{ "motion", "uff"  },
	{ "up", "u"  },
	{ "cancel", "u"  },
};

static const struct brei_message eis_touchscreen_events[] = {
	{ "destroyed", "u" },
	{ "down", "uff" },
	{ "motion", "uff" },
	{ "up", "u" },
	{ "cancel", "u" },
};

static const struct brei_message eis_touchscreen_incoming[] = {
	{ "release", "" },
	{ "down", "uff" },
	{ "motion", "uff" },
	{ "up", "u" },
	{ "cancel", "u" },
};

const struct brei_interface eis_touchscreen_proto_interface = {
    .name = "eis_touchscreen", .version = 2,
    .nrequests = 5, .requests = eis_touchscreen_requests,
    .nevents = 5, .events = eis_touchscreen_events,
    .nincoming = 5, .incoming = eis_touchscreen_incoming,
    .dispatcher = (brei_event_dispatcher)eis_touchscreen_dispatcher,
};

/***************************************************************************
 * Interface: eis_text                                                     *
 ***************************************************************************/

/* returns the protocol interface from the given struct, see the dispatcher */
const struct eis_text_interface *eis_text_get_interface(struct eis_text * eis_text);

/* returns the message sending context from the given struct */
struct eis_client * eis_text_get_client(struct eis_text * eis_text);

/* Returns the protocol object id from the given struct */
const struct brei_object *
eis_text_get_proto_object(struct eis_text * eis_text);

/* request opcodes */
#define EIS_TEXT_REQUEST_RELEASE                      0
#define EIS_TEXT_REQUEST_KEYSYM                       1
#define EIS_TEXT_REQUEST_UTF8                         2

/* event opcodes */
#define EIS_TEXT_EVENT_DESTROYED                      0
#define EIS_TEXT_EVENT_KEYSYM                         1
#define EIS_TEXT_EVENT_UTF8                           2

/* Message sender functions */
int
eis_text_event_destroyed(struct eis_text * eis_text, uint32_t serial)
{
	if (!eis_text)
		return -ENOENT;

	const struct brei_object *obj = eis_text_get_proto_object(eis_text);
	struct eis_client * ctx = eis_text_get_client(eis_text);

	if (obj->version < EIS_TEXT_EVENT_DESTROYED_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TEXT_EVENT_DESTROYED, "u",
		1, serial);
}

int
eis_text_event_keysym(struct eis_text * eis_text, uint32_t keysym, uint32_t state)
{
	if (!eis_text)
		return -ENOENT;

	const struct brei_object *obj = eis_text_get_proto_object(eis_text);
	struct eis_client * ctx = eis_text_get_client(eis_text);

	if (obj->version < EIS_TEXT_EVENT_KEYSYM_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TEXT_EVENT_KEYSYM, "uu",
		2, keysym, state);
}

int
eis_text_event_utf8(struct eis_text * eis_text, const char * text)
{
	if (!eis_text)
		return -ENOENT;

	const struct brei_object *obj = eis_text_get_proto_object(eis_text);
	struct eis_client * ctx = eis_text_get_client(eis_text);

	if (obj->version < EIS_TEXT_EVENT_UTF8_SINCE_VERSION)
		return -ENOTSUP;

	return eis_client_send_message(
		ctx, obj, EIS_TEXT_EVENT_UTF8, "s",
		1, text);
}


/**
 * The dispatcher for the eis_text interface is the function called by
 * brei with the messages parsed from the wire.
 */
static struct brei_result *
eis_text_dispatcher(
	struct eis_text * eis_text,
	uint32_t opcode,
	size_t nargs,
	union brei_arg *args
) {
	const struct eis_text_interface *interface = eis_text_get_interface(eis_text);
	const struct brei_object *obj = eis_text_get_proto_object(eis_text);

	if (!interface)
		return NULL;

	switch (opcode) {
	case EIS_TEXT_REQUEST_RELEASE:
		if (obj->version < EIS_TEXT_REQUEST_RELEASE_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->release != NULL);
		return interface->release(eis_text);
	case EIS_TEXT_REQUEST_KEYSYM:
		if (obj->version < EIS_TEXT_REQUEST_KEYSYM_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->keysym != NULL);
		return interface->keysym(eis_text, (args + 0)->u, (args + 1)->u);
	case EIS_TEXT_REQUEST_UTF8:
		if (obj->version < EIS_TEXT_REQUEST_UTF8_SINCE_VERSION)
			return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
					       "Opcode %u not supported in this interface version", opcode);
		assert(interface->utf8 != NULL);
		return interface->utf8(eis_text, (args + 0)->s);
	}
	return brei_result_new(BREI_CONNECTION_DISCONNECT_REASON_ERROR,
			       "Opcode %u not supported in this interface version", opcode);
}

static const struct brei_message eis_text_requests[] = {
	{ "release", ""  },
	{ "keysym", "uu"  },
	{ "utf8", "s"  },
};

static const struct brei_message eis_text_events[] = {
	{ "destroyed", "u" },
	{ "keysym", "uu" },
	{ "utf8", "s" },
};

static const struct brei_message eis_text_incoming[] = {
	{ "release", "" },
	{ "keysym", "uu" },
	{ "utf8", "s" },
};

const struct brei_interface eis_text_proto_interface = {
    .name = "eis_text", .version = 1,
    .nrequests = 3, .requests = eis_text_requests,
    .nevents = 3, .events = eis_text_events,
    .nincoming = 3, .incoming = eis_text_incoming,
    .dispatcher = (brei_event_dispatcher)eis_text_dispatcher,
};

