/*
 * AUTOGENERATED - DO NOT EDIT
 *
 * This file is generated from protocol.xml by mir_wayland_generator
 */

#include "protocol_wrapper.h"

#include <boost/exception/diagnostic_information.hpp>
#include <wayland-server-core.h>

#include "mir/log.h"
#include "mir/wayland/protocol_error.h"
#include "mir/wayland/client.h"

namespace mir
{
namespace wayland
{
extern struct wl_interface const wl_buffer_interface_data;
extern struct wl_interface const wl_callback_interface_data;
extern struct wl_interface const wl_compositor_interface_data;
extern struct wl_interface const wl_data_device_interface_data;
extern struct wl_interface const wl_data_device_manager_interface_data;
extern struct wl_interface const wl_data_offer_interface_data;
extern struct wl_interface const wl_data_source_interface_data;
extern struct wl_interface const wl_keyboard_interface_data;
extern struct wl_interface const wl_output_interface_data;
extern struct wl_interface const wl_pointer_interface_data;
extern struct wl_interface const wl_region_interface_data;
extern struct wl_interface const wl_seat_interface_data;
extern struct wl_interface const wl_shell_interface_data;
extern struct wl_interface const wl_shell_surface_interface_data;
extern struct wl_interface const wl_shm_interface_data;
extern struct wl_interface const wl_shm_pool_interface_data;
extern struct wl_interface const wl_subcompositor_interface_data;
extern struct wl_interface const wl_subsurface_interface_data;
extern struct wl_interface const wl_surface_interface_data;
extern struct wl_interface const wl_touch_interface_data;
}
}

namespace mw = mir::wayland;

namespace
{
struct wl_interface const* all_null_types [] {
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    nullptr};
}

// Callback

struct mw::Callback::Thunks
{
    static int const supported_version;

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Callback*>(wl_resource_get_user_data(resource));
    }

    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Callback::Thunks::supported_version = 1;

mw::Callback::Callback(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Callback::~Callback()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Callback::send_done_event(uint32_t callback_data) const
{
    wl_resource_post_event(resource, Opcode::done, callback_data);
}

bool mw::Callback::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_callback_interface_data, Thunks::request_vtable);
}

void mw::Callback::destroy_and_delete() const
{
    // Will result in this object being deleted
    wl_resource_destroy(resource);
}

struct wl_message const mw::Callback::Thunks::event_messages[] {
    {"done", "u", all_null_types}};

void const* mw::Callback::Thunks::request_vtable[] {
    nullptr};

mw::Callback* mw::Callback::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_callback_interface_data, Callback::Thunks::request_vtable))
    {
        return static_cast<Callback*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Compositor

struct mw::Compositor::Thunks
{
    static int const supported_version;

    static void create_surface_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_surface_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Compositor*>(wl_resource_get_user_data(resource));
            me->create_surface(id_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Compositor::create_surface()");
        }
    }

    static void create_region_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_region_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Compositor*>(wl_resource_get_user_data(resource));
            me->create_region(id_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Compositor::create_region()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Compositor*>(wl_resource_get_user_data(resource));
    }

    static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)
    {
        auto me = static_cast<Compositor::Global*>(data);
        auto resource = wl_resource_create(
            client,
            &wl_compositor_interface_data,
            std::min((int)version, Thunks::supported_version),
            id);
        if (resource == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            me->bind(resource);
        }
        catch(...)
        {
            internal_error_processing_request(client, "Compositor global bind");
        }
    }

    static struct wl_interface const* create_surface_types[];
    static struct wl_interface const* create_region_types[];
    static struct wl_message const request_messages[];
    static void const* request_vtable[];
};

int const mw::Compositor::Thunks::supported_version = 4;

mw::Compositor::Compositor(struct wl_resource* resource, Version<4>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Compositor::~Compositor()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

bool mw::Compositor::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_compositor_interface_data, Thunks::request_vtable);
}

void mw::Compositor::destroy_and_delete() const
{
    // Will result in this object being deleted
    wl_resource_destroy(resource);
}

mw::Compositor::Global::Global(wl_display* display, Version<4>)
    : wayland::Global{
          wl_global_create(
              display,
              &wl_compositor_interface_data,
              Thunks::supported_version,
              this,
              &Thunks::bind_thunk)}
{
}

auto mw::Compositor::Global::interface_name() const -> char const*
{
    return Compositor::interface_name;
}

struct wl_interface const* mw::Compositor::Thunks::create_surface_types[] {
    &wl_surface_interface_data};

struct wl_interface const* mw::Compositor::Thunks::create_region_types[] {
    &wl_region_interface_data};

struct wl_message const mw::Compositor::Thunks::request_messages[] {
    {"create_surface", "n", create_surface_types},
    {"create_region", "n", create_region_types}};

void const* mw::Compositor::Thunks::request_vtable[] {
    (void*)Thunks::create_surface_thunk,
    (void*)Thunks::create_region_thunk};

mw::Compositor* mw::Compositor::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_compositor_interface_data, Compositor::Thunks::request_vtable))
    {
        return static_cast<Compositor*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// ShmPool

struct mw::ShmPool::Thunks
{
    static int const supported_version;

    static void create_buffer_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_buffer_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<ShmPool*>(wl_resource_get_user_data(resource));
            me->create_buffer(id_resolved, offset, width, height, stride, format);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShmPool::create_buffer()");
        }
    }

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<ShmPool*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShmPool::destroy()");
        }
    }

    static void resize_thunk(struct wl_client* client, struct wl_resource* resource, int32_t size)
    {
        try
        {
            auto me = static_cast<ShmPool*>(wl_resource_get_user_data(resource));
            me->resize(size);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShmPool::resize()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<ShmPool*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* create_buffer_types[];
    static struct wl_message const request_messages[];
    static void const* request_vtable[];
};

int const mw::ShmPool::Thunks::supported_version = 1;

mw::ShmPool::ShmPool(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::ShmPool::~ShmPool()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

bool mw::ShmPool::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_shm_pool_interface_data, Thunks::request_vtable);
}

struct wl_interface const* mw::ShmPool::Thunks::create_buffer_types[] {
    &wl_buffer_interface_data,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    nullptr};

struct wl_message const mw::ShmPool::Thunks::request_messages[] {
    {"create_buffer", "niiiiu", create_buffer_types},
    {"destroy", "", all_null_types},
    {"resize", "i", all_null_types}};

void const* mw::ShmPool::Thunks::request_vtable[] {
    (void*)Thunks::create_buffer_thunk,
    (void*)Thunks::destroy_thunk,
    (void*)Thunks::resize_thunk};

mw::ShmPool* mw::ShmPool::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_shm_pool_interface_data, ShmPool::Thunks::request_vtable))
    {
        return static_cast<ShmPool*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Shm

struct mw::Shm::Thunks
{
    static int const supported_version;

    static void create_pool_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, int32_t fd, int32_t size)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_shm_pool_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        mir::Fd fd_resolved{fd};
        try
        {
            auto me = static_cast<Shm*>(wl_resource_get_user_data(resource));
            me->create_pool(id_resolved, fd_resolved, size);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Shm::create_pool()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Shm*>(wl_resource_get_user_data(resource));
    }

    static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)
    {
        auto me = static_cast<Shm::Global*>(data);
        auto resource = wl_resource_create(
            client,
            &wl_shm_interface_data,
            std::min((int)version, Thunks::supported_version),
            id);
        if (resource == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            me->bind(resource);
        }
        catch(...)
        {
            internal_error_processing_request(client, "Shm global bind");
        }
    }

    static struct wl_interface const* create_pool_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Shm::Thunks::supported_version = 1;

mw::Shm::Shm(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Shm::~Shm()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Shm::send_format_event(uint32_t format) const
{
    wl_resource_post_event(resource, Opcode::format, format);
}

bool mw::Shm::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_shm_interface_data, Thunks::request_vtable);
}

void mw::Shm::destroy_and_delete() const
{
    // Will result in this object being deleted
    wl_resource_destroy(resource);
}

uint32_t const mw::Shm::Error::invalid_format;
uint32_t const mw::Shm::Error::invalid_stride;
uint32_t const mw::Shm::Error::invalid_fd;
uint32_t const mw::Shm::Format::argb8888;
uint32_t const mw::Shm::Format::xrgb8888;
uint32_t const mw::Shm::Format::c8;
uint32_t const mw::Shm::Format::rgb332;
uint32_t const mw::Shm::Format::bgr233;
uint32_t const mw::Shm::Format::xrgb4444;
uint32_t const mw::Shm::Format::xbgr4444;
uint32_t const mw::Shm::Format::rgbx4444;
uint32_t const mw::Shm::Format::bgrx4444;
uint32_t const mw::Shm::Format::argb4444;
uint32_t const mw::Shm::Format::abgr4444;
uint32_t const mw::Shm::Format::rgba4444;
uint32_t const mw::Shm::Format::bgra4444;
uint32_t const mw::Shm::Format::xrgb1555;
uint32_t const mw::Shm::Format::xbgr1555;
uint32_t const mw::Shm::Format::rgbx5551;
uint32_t const mw::Shm::Format::bgrx5551;
uint32_t const mw::Shm::Format::argb1555;
uint32_t const mw::Shm::Format::abgr1555;
uint32_t const mw::Shm::Format::rgba5551;
uint32_t const mw::Shm::Format::bgra5551;
uint32_t const mw::Shm::Format::rgb565;
uint32_t const mw::Shm::Format::bgr565;
uint32_t const mw::Shm::Format::rgb888;
uint32_t const mw::Shm::Format::bgr888;
uint32_t const mw::Shm::Format::xbgr8888;
uint32_t const mw::Shm::Format::rgbx8888;
uint32_t const mw::Shm::Format::bgrx8888;
uint32_t const mw::Shm::Format::abgr8888;
uint32_t const mw::Shm::Format::rgba8888;
uint32_t const mw::Shm::Format::bgra8888;
uint32_t const mw::Shm::Format::xrgb2101010;
uint32_t const mw::Shm::Format::xbgr2101010;
uint32_t const mw::Shm::Format::rgbx1010102;
uint32_t const mw::Shm::Format::bgrx1010102;
uint32_t const mw::Shm::Format::argb2101010;
uint32_t const mw::Shm::Format::abgr2101010;
uint32_t const mw::Shm::Format::rgba1010102;
uint32_t const mw::Shm::Format::bgra1010102;
uint32_t const mw::Shm::Format::yuyv;
uint32_t const mw::Shm::Format::yvyu;
uint32_t const mw::Shm::Format::uyvy;
uint32_t const mw::Shm::Format::vyuy;
uint32_t const mw::Shm::Format::ayuv;
uint32_t const mw::Shm::Format::nv12;
uint32_t const mw::Shm::Format::nv21;
uint32_t const mw::Shm::Format::nv16;
uint32_t const mw::Shm::Format::nv61;
uint32_t const mw::Shm::Format::yuv410;
uint32_t const mw::Shm::Format::yvu410;
uint32_t const mw::Shm::Format::yuv411;
uint32_t const mw::Shm::Format::yvu411;
uint32_t const mw::Shm::Format::yuv420;
uint32_t const mw::Shm::Format::yvu420;
uint32_t const mw::Shm::Format::yuv422;
uint32_t const mw::Shm::Format::yvu422;
uint32_t const mw::Shm::Format::yuv444;
uint32_t const mw::Shm::Format::yvu444;

mw::Shm::Global::Global(wl_display* display, Version<1>)
    : wayland::Global{
          wl_global_create(
              display,
              &wl_shm_interface_data,
              Thunks::supported_version,
              this,
              &Thunks::bind_thunk)}
{
}

auto mw::Shm::Global::interface_name() const -> char const*
{
    return Shm::interface_name;
}

struct wl_interface const* mw::Shm::Thunks::create_pool_types[] {
    &wl_shm_pool_interface_data,
    nullptr,
    nullptr};

struct wl_message const mw::Shm::Thunks::request_messages[] {
    {"create_pool", "nhi", create_pool_types}};

struct wl_message const mw::Shm::Thunks::event_messages[] {
    {"format", "u", all_null_types}};

void const* mw::Shm::Thunks::request_vtable[] {
    (void*)Thunks::create_pool_thunk};

mw::Shm* mw::Shm::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_shm_interface_data, Shm::Thunks::request_vtable))
    {
        return static_cast<Shm*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Buffer

struct mw::Buffer::Thunks
{
    static int const supported_version;

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Buffer*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Buffer::destroy()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Buffer*>(wl_resource_get_user_data(resource));
    }

    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Buffer::Thunks::supported_version = 1;

mw::Buffer::Buffer(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Buffer::~Buffer()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Buffer::send_release_event() const
{
    wl_resource_post_event(resource, Opcode::release);
}

bool mw::Buffer::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_buffer_interface_data, Thunks::request_vtable);
}

struct wl_message const mw::Buffer::Thunks::request_messages[] {
    {"destroy", "", all_null_types}};

struct wl_message const mw::Buffer::Thunks::event_messages[] {
    {"release", "", all_null_types}};

void const* mw::Buffer::Thunks::request_vtable[] {
    (void*)Thunks::destroy_thunk};

mw::Buffer* mw::Buffer::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_buffer_interface_data, Buffer::Thunks::request_vtable))
    {
        return static_cast<Buffer*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// DataOffer

struct mw::DataOffer::Thunks
{
    static int const supported_version;

    static void accept_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t serial, char const* mime_type)
    {
        std::optional<std::string> mime_type_resolved;
        if (mime_type != nullptr)
        {
            mime_type_resolved = {mime_type};
        }
        try
        {
            auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
            me->accept(serial, mime_type_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataOffer::accept()");
        }
    }

    static void receive_thunk(struct wl_client* client, struct wl_resource* resource, char const* mime_type, int32_t fd)
    {
        mir::Fd fd_resolved{fd};
        try
        {
            auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
            me->receive(mime_type, fd_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataOffer::receive()");
        }
    }

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataOffer::destroy()");
        }
    }

    static void finish_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
            me->finish();
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataOffer::finish()");
        }
    }

    static void set_actions_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t dnd_actions, uint32_t preferred_action)
    {
        try
        {
            auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
            me->set_actions(dnd_actions, preferred_action);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataOffer::set_actions()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<DataOffer*>(wl_resource_get_user_data(resource));
    }

    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::DataOffer::Thunks::supported_version = 3;

mw::DataOffer::DataOffer(DataDevice const& parent)
    : Resource{wl_resource_create(
          wl_resource_get_client(parent.resource),
          &wl_data_offer_interface_data,
          wl_resource_get_version(parent.resource), 0)}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::DataOffer::~DataOffer()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::DataOffer::send_offer_event(std::string const& mime_type) const
{
    const char* mime_type_resolved = mime_type.c_str();
    wl_resource_post_event(resource, Opcode::offer, mime_type_resolved);
}

bool mw::DataOffer::version_supports_source_actions()
{
    return wl_resource_get_version(resource) >= 3;
}

void mw::DataOffer::send_source_actions_event_if_supported(uint32_t source_actions) const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::source_actions, source_actions);
    }
}

void mw::DataOffer::send_source_actions_event(uint32_t source_actions) const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::source_actions, source_actions);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "source_actions", 3);
    }
}

bool mw::DataOffer::version_supports_action()
{
    return wl_resource_get_version(resource) >= 3;
}

void mw::DataOffer::send_action_event_if_supported(uint32_t dnd_action) const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::action, dnd_action);
    }
}

void mw::DataOffer::send_action_event(uint32_t dnd_action) const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::action, dnd_action);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "action", 3);
    }
}

bool mw::DataOffer::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_data_offer_interface_data, Thunks::request_vtable);
}

uint32_t const mw::DataOffer::Error::invalid_finish;
uint32_t const mw::DataOffer::Error::invalid_action_mask;
uint32_t const mw::DataOffer::Error::invalid_action;
uint32_t const mw::DataOffer::Error::invalid_offer;

struct wl_message const mw::DataOffer::Thunks::request_messages[] {
    {"accept", "u?s", all_null_types},
    {"receive", "sh", all_null_types},
    {"destroy", "", all_null_types},
    {"finish", "3", all_null_types},
    {"set_actions", "3uu", all_null_types}};

struct wl_message const mw::DataOffer::Thunks::event_messages[] {
    {"offer", "s", all_null_types},
    {"source_actions", "3u", all_null_types},
    {"action", "3u", all_null_types}};

void const* mw::DataOffer::Thunks::request_vtable[] {
    (void*)Thunks::accept_thunk,
    (void*)Thunks::receive_thunk,
    (void*)Thunks::destroy_thunk,
    (void*)Thunks::finish_thunk,
    (void*)Thunks::set_actions_thunk};

mw::DataOffer* mw::DataOffer::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_data_offer_interface_data, DataOffer::Thunks::request_vtable))
    {
        return static_cast<DataOffer*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// DataSource

struct mw::DataSource::Thunks
{
    static int const supported_version;

    static void offer_thunk(struct wl_client* client, struct wl_resource* resource, char const* mime_type)
    {
        try
        {
            auto me = static_cast<DataSource*>(wl_resource_get_user_data(resource));
            me->offer(mime_type);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataSource::offer()");
        }
    }

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<DataSource*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataSource::destroy()");
        }
    }

    static void set_actions_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t dnd_actions)
    {
        try
        {
            auto me = static_cast<DataSource*>(wl_resource_get_user_data(resource));
            me->set_actions(dnd_actions);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataSource::set_actions()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<DataSource*>(wl_resource_get_user_data(resource));
    }

    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::DataSource::Thunks::supported_version = 3;

mw::DataSource::DataSource(struct wl_resource* resource, Version<3>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::DataSource::~DataSource()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::DataSource::send_target_event(std::optional<std::string> const& mime_type) const
{
    const char* mime_type_resolved = nullptr;
    if (mime_type)
    {
        mime_type_resolved = mime_type.value().c_str();
    }
    wl_resource_post_event(resource, Opcode::target, mime_type_resolved);
}

void mw::DataSource::send_send_event(std::string const& mime_type, mir::Fd fd) const
{
    const char* mime_type_resolved = mime_type.c_str();
    int32_t fd_resolved{fd};
    wl_resource_post_event(resource, Opcode::send, mime_type_resolved, fd_resolved);
}

void mw::DataSource::send_cancelled_event() const
{
    wl_resource_post_event(resource, Opcode::cancelled);
}

bool mw::DataSource::version_supports_dnd_drop_performed()
{
    return wl_resource_get_version(resource) >= 3;
}

void mw::DataSource::send_dnd_drop_performed_event_if_supported() const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::dnd_drop_performed);
    }
}

void mw::DataSource::send_dnd_drop_performed_event() const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::dnd_drop_performed);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "dnd_drop_performed", 3);
    }
}

bool mw::DataSource::version_supports_dnd_finished()
{
    return wl_resource_get_version(resource) >= 3;
}

void mw::DataSource::send_dnd_finished_event_if_supported() const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::dnd_finished);
    }
}

void mw::DataSource::send_dnd_finished_event() const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::dnd_finished);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "dnd_finished", 3);
    }
}

bool mw::DataSource::version_supports_action()
{
    return wl_resource_get_version(resource) >= 3;
}

void mw::DataSource::send_action_event_if_supported(uint32_t dnd_action) const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::action, dnd_action);
    }
}

void mw::DataSource::send_action_event(uint32_t dnd_action) const
{
    if (wl_resource_get_version(resource) >= 3)
    {
        wl_resource_post_event(resource, Opcode::action, dnd_action);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "action", 3);
    }
}

bool mw::DataSource::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_data_source_interface_data, Thunks::request_vtable);
}

uint32_t const mw::DataSource::Error::invalid_action_mask;
uint32_t const mw::DataSource::Error::invalid_source;

struct wl_message const mw::DataSource::Thunks::request_messages[] {
    {"offer", "s", all_null_types},
    {"destroy", "", all_null_types},
    {"set_actions", "3u", all_null_types}};

struct wl_message const mw::DataSource::Thunks::event_messages[] {
    {"target", "?s", all_null_types},
    {"send", "sh", all_null_types},
    {"cancelled", "", all_null_types},
    {"dnd_drop_performed", "3", all_null_types},
    {"dnd_finished", "3", all_null_types},
    {"action", "3u", all_null_types}};

void const* mw::DataSource::Thunks::request_vtable[] {
    (void*)Thunks::offer_thunk,
    (void*)Thunks::destroy_thunk,
    (void*)Thunks::set_actions_thunk};

mw::DataSource* mw::DataSource::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_data_source_interface_data, DataSource::Thunks::request_vtable))
    {
        return static_cast<DataSource*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// DataDevice

struct mw::DataDevice::Thunks
{
    static int const supported_version;

    static void start_drag_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* source, struct wl_resource* origin, struct wl_resource* icon, uint32_t serial)
    {
        std::optional<struct wl_resource*> source_resolved;
        if (source != nullptr)
        {
            source_resolved = {source};
        }
        std::optional<struct wl_resource*> icon_resolved;
        if (icon != nullptr)
        {
            icon_resolved = {icon};
        }
        try
        {
            auto me = static_cast<DataDevice*>(wl_resource_get_user_data(resource));
            me->start_drag(source_resolved, origin, icon_resolved, serial);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataDevice::start_drag()");
        }
    }

    static void set_selection_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* source, uint32_t serial)
    {
        std::optional<struct wl_resource*> source_resolved;
        if (source != nullptr)
        {
            source_resolved = {source};
        }
        try
        {
            auto me = static_cast<DataDevice*>(wl_resource_get_user_data(resource));
            me->set_selection(source_resolved, serial);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataDevice::set_selection()");
        }
    }

    static void release_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<DataDevice*>(wl_resource_get_user_data(resource));
            me->release();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataDevice::release()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<DataDevice*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* start_drag_types[];
    static struct wl_interface const* set_selection_types[];
    static struct wl_interface const* data_offer_types[];
    static struct wl_interface const* enter_types[];
    static struct wl_interface const* selection_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::DataDevice::Thunks::supported_version = 3;

mw::DataDevice::DataDevice(struct wl_resource* resource, Version<3>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::DataDevice::~DataDevice()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::DataDevice::send_data_offer_event(struct wl_resource* id) const
{
    wl_resource_post_event(resource, Opcode::data_offer, id);
}

void mw::DataDevice::send_enter_event(uint32_t serial, struct wl_resource* surface, double x, double y, std::optional<struct wl_resource*> const& id) const
{
    wl_fixed_t x_resolved{wl_fixed_from_double(x)};
    wl_fixed_t y_resolved{wl_fixed_from_double(y)};
    struct wl_resource* id_resolved = nullptr;
    if (id)
    {
        id_resolved = id.value();
    }
    wl_resource_post_event(resource, Opcode::enter, serial, surface, x_resolved, y_resolved, id_resolved);
}

void mw::DataDevice::send_leave_event() const
{
    wl_resource_post_event(resource, Opcode::leave);
}

void mw::DataDevice::send_motion_event(uint32_t time, double x, double y) const
{
    wl_fixed_t x_resolved{wl_fixed_from_double(x)};
    wl_fixed_t y_resolved{wl_fixed_from_double(y)};
    wl_resource_post_event(resource, Opcode::motion, time, x_resolved, y_resolved);
}

void mw::DataDevice::send_drop_event() const
{
    wl_resource_post_event(resource, Opcode::drop);
}

void mw::DataDevice::send_selection_event(std::optional<struct wl_resource*> const& id) const
{
    struct wl_resource* id_resolved = nullptr;
    if (id)
    {
        id_resolved = id.value();
    }
    wl_resource_post_event(resource, Opcode::selection, id_resolved);
}

bool mw::DataDevice::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_data_device_interface_data, Thunks::request_vtable);
}

uint32_t const mw::DataDevice::Error::role;

struct wl_interface const* mw::DataDevice::Thunks::start_drag_types[] {
    &wl_data_source_interface_data,
    &wl_surface_interface_data,
    &wl_surface_interface_data,
    nullptr};

struct wl_interface const* mw::DataDevice::Thunks::set_selection_types[] {
    &wl_data_source_interface_data,
    nullptr};

struct wl_interface const* mw::DataDevice::Thunks::data_offer_types[] {
    &wl_data_offer_interface_data};

struct wl_interface const* mw::DataDevice::Thunks::enter_types[] {
    nullptr,
    &wl_surface_interface_data,
    nullptr,
    nullptr,
    &wl_data_offer_interface_data};

struct wl_interface const* mw::DataDevice::Thunks::selection_types[] {
    &wl_data_offer_interface_data};

struct wl_message const mw::DataDevice::Thunks::request_messages[] {
    {"start_drag", "?oo?ou", start_drag_types},
    {"set_selection", "?ou", set_selection_types},
    {"release", "2", all_null_types}};

struct wl_message const mw::DataDevice::Thunks::event_messages[] {
    {"data_offer", "n", data_offer_types},
    {"enter", "uoff?o", enter_types},
    {"leave", "", all_null_types},
    {"motion", "uff", all_null_types},
    {"drop", "", all_null_types},
    {"selection", "?o", selection_types}};

void const* mw::DataDevice::Thunks::request_vtable[] {
    (void*)Thunks::start_drag_thunk,
    (void*)Thunks::set_selection_thunk,
    (void*)Thunks::release_thunk};

mw::DataDevice* mw::DataDevice::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_data_device_interface_data, DataDevice::Thunks::request_vtable))
    {
        return static_cast<DataDevice*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// DataDeviceManager

struct mw::DataDeviceManager::Thunks
{
    static int const supported_version;

    static void create_data_source_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_data_source_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<DataDeviceManager*>(wl_resource_get_user_data(resource));
            me->create_data_source(id_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataDeviceManager::create_data_source()");
        }
    }

    static void get_data_device_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* seat)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_data_device_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<DataDeviceManager*>(wl_resource_get_user_data(resource));
            me->get_data_device(id_resolved, seat);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataDeviceManager::get_data_device()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<DataDeviceManager*>(wl_resource_get_user_data(resource));
    }

    static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)
    {
        auto me = static_cast<DataDeviceManager::Global*>(data);
        auto resource = wl_resource_create(
            client,
            &wl_data_device_manager_interface_data,
            std::min((int)version, Thunks::supported_version),
            id);
        if (resource == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            me->bind(resource);
        }
        catch(...)
        {
            internal_error_processing_request(client, "DataDeviceManager global bind");
        }
    }

    static struct wl_interface const* create_data_source_types[];
    static struct wl_interface const* get_data_device_types[];
    static struct wl_message const request_messages[];
    static void const* request_vtable[];
};

int const mw::DataDeviceManager::Thunks::supported_version = 3;

mw::DataDeviceManager::DataDeviceManager(struct wl_resource* resource, Version<3>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::DataDeviceManager::~DataDeviceManager()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

bool mw::DataDeviceManager::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_data_device_manager_interface_data, Thunks::request_vtable);
}

void mw::DataDeviceManager::destroy_and_delete() const
{
    // Will result in this object being deleted
    wl_resource_destroy(resource);
}

uint32_t const mw::DataDeviceManager::DndAction::none;
uint32_t const mw::DataDeviceManager::DndAction::copy;
uint32_t const mw::DataDeviceManager::DndAction::move;
uint32_t const mw::DataDeviceManager::DndAction::ask;

mw::DataDeviceManager::Global::Global(wl_display* display, Version<3>)
    : wayland::Global{
          wl_global_create(
              display,
              &wl_data_device_manager_interface_data,
              Thunks::supported_version,
              this,
              &Thunks::bind_thunk)}
{
}

auto mw::DataDeviceManager::Global::interface_name() const -> char const*
{
    return DataDeviceManager::interface_name;
}

struct wl_interface const* mw::DataDeviceManager::Thunks::create_data_source_types[] {
    &wl_data_source_interface_data};

struct wl_interface const* mw::DataDeviceManager::Thunks::get_data_device_types[] {
    &wl_data_device_interface_data,
    &wl_seat_interface_data};

struct wl_message const mw::DataDeviceManager::Thunks::request_messages[] {
    {"create_data_source", "n", create_data_source_types},
    {"get_data_device", "no", get_data_device_types}};

void const* mw::DataDeviceManager::Thunks::request_vtable[] {
    (void*)Thunks::create_data_source_thunk,
    (void*)Thunks::get_data_device_thunk};

mw::DataDeviceManager* mw::DataDeviceManager::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_data_device_manager_interface_data, DataDeviceManager::Thunks::request_vtable))
    {
        return static_cast<DataDeviceManager*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Shell

struct mw::Shell::Thunks
{
    static int const supported_version;

    static void get_shell_surface_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* surface)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_shell_surface_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Shell*>(wl_resource_get_user_data(resource));
            me->get_shell_surface(id_resolved, surface);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Shell::get_shell_surface()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Shell*>(wl_resource_get_user_data(resource));
    }

    static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)
    {
        auto me = static_cast<Shell::Global*>(data);
        auto resource = wl_resource_create(
            client,
            &wl_shell_interface_data,
            std::min((int)version, Thunks::supported_version),
            id);
        if (resource == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            me->bind(resource);
        }
        catch(...)
        {
            internal_error_processing_request(client, "Shell global bind");
        }
    }

    static struct wl_interface const* get_shell_surface_types[];
    static struct wl_message const request_messages[];
    static void const* request_vtable[];
};

int const mw::Shell::Thunks::supported_version = 1;

mw::Shell::Shell(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Shell::~Shell()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

bool mw::Shell::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_shell_interface_data, Thunks::request_vtable);
}

void mw::Shell::destroy_and_delete() const
{
    // Will result in this object being deleted
    wl_resource_destroy(resource);
}

uint32_t const mw::Shell::Error::role;

mw::Shell::Global::Global(wl_display* display, Version<1>)
    : wayland::Global{
          wl_global_create(
              display,
              &wl_shell_interface_data,
              Thunks::supported_version,
              this,
              &Thunks::bind_thunk)}
{
}

auto mw::Shell::Global::interface_name() const -> char const*
{
    return Shell::interface_name;
}

struct wl_interface const* mw::Shell::Thunks::get_shell_surface_types[] {
    &wl_shell_surface_interface_data,
    &wl_surface_interface_data};

struct wl_message const mw::Shell::Thunks::request_messages[] {
    {"get_shell_surface", "no", get_shell_surface_types}};

void const* mw::Shell::Thunks::request_vtable[] {
    (void*)Thunks::get_shell_surface_thunk};

mw::Shell* mw::Shell::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_shell_interface_data, Shell::Thunks::request_vtable))
    {
        return static_cast<Shell*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// ShellSurface

struct mw::ShellSurface::Thunks
{
    static int const supported_version;

    static void pong_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t serial)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->pong(serial);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::pong()");
        }
    }

    static void move_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* seat, uint32_t serial)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->move(seat, serial);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::move()");
        }
    }

    static void resize_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* seat, uint32_t serial, uint32_t edges)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->resize(seat, serial, edges);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::resize()");
        }
    }

    static void set_toplevel_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->set_toplevel();
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::set_toplevel()");
        }
    }

    static void set_transient_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* parent, int32_t x, int32_t y, uint32_t flags)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->set_transient(parent, x, y, flags);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::set_transient()");
        }
    }

    static void set_fullscreen_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t method, uint32_t framerate, struct wl_resource* output)
    {
        std::optional<struct wl_resource*> output_resolved;
        if (output != nullptr)
        {
            output_resolved = {output};
        }
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->set_fullscreen(method, framerate, output_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::set_fullscreen()");
        }
    }

    static void set_popup_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* seat, uint32_t serial, struct wl_resource* parent, int32_t x, int32_t y, uint32_t flags)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->set_popup(seat, serial, parent, x, y, flags);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::set_popup()");
        }
    }

    static void set_maximized_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* output)
    {
        std::optional<struct wl_resource*> output_resolved;
        if (output != nullptr)
        {
            output_resolved = {output};
        }
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->set_maximized(output_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::set_maximized()");
        }
    }

    static void set_title_thunk(struct wl_client* client, struct wl_resource* resource, char const* title)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->set_title(title);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::set_title()");
        }
    }

    static void set_class_thunk(struct wl_client* client, struct wl_resource* resource, char const* class_)
    {
        try
        {
            auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
            me->set_class(class_);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "ShellSurface::set_class()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* move_types[];
    static struct wl_interface const* resize_types[];
    static struct wl_interface const* set_transient_types[];
    static struct wl_interface const* set_fullscreen_types[];
    static struct wl_interface const* set_popup_types[];
    static struct wl_interface const* set_maximized_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::ShellSurface::Thunks::supported_version = 1;

mw::ShellSurface::ShellSurface(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::ShellSurface::~ShellSurface()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::ShellSurface::send_ping_event(uint32_t serial) const
{
    wl_resource_post_event(resource, Opcode::ping, serial);
}

void mw::ShellSurface::send_configure_event(uint32_t edges, int32_t width, int32_t height) const
{
    wl_resource_post_event(resource, Opcode::configure, edges, width, height);
}

void mw::ShellSurface::send_popup_done_event() const
{
    wl_resource_post_event(resource, Opcode::popup_done);
}

bool mw::ShellSurface::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_shell_surface_interface_data, Thunks::request_vtable);
}

void mw::ShellSurface::destroy_and_delete() const
{
    // Will result in this object being deleted
    wl_resource_destroy(resource);
}

uint32_t const mw::ShellSurface::Resize::none;
uint32_t const mw::ShellSurface::Resize::top;
uint32_t const mw::ShellSurface::Resize::bottom;
uint32_t const mw::ShellSurface::Resize::left;
uint32_t const mw::ShellSurface::Resize::top_left;
uint32_t const mw::ShellSurface::Resize::bottom_left;
uint32_t const mw::ShellSurface::Resize::right;
uint32_t const mw::ShellSurface::Resize::top_right;
uint32_t const mw::ShellSurface::Resize::bottom_right;
uint32_t const mw::ShellSurface::Transient::inactive;
uint32_t const mw::ShellSurface::FullscreenMethod::default_;
uint32_t const mw::ShellSurface::FullscreenMethod::scale;
uint32_t const mw::ShellSurface::FullscreenMethod::driver;
uint32_t const mw::ShellSurface::FullscreenMethod::fill;

struct wl_interface const* mw::ShellSurface::Thunks::move_types[] {
    &wl_seat_interface_data,
    nullptr};

struct wl_interface const* mw::ShellSurface::Thunks::resize_types[] {
    &wl_seat_interface_data,
    nullptr,
    nullptr};

struct wl_interface const* mw::ShellSurface::Thunks::set_transient_types[] {
    &wl_surface_interface_data,
    nullptr,
    nullptr,
    nullptr};

struct wl_interface const* mw::ShellSurface::Thunks::set_fullscreen_types[] {
    nullptr,
    nullptr,
    &wl_output_interface_data};

struct wl_interface const* mw::ShellSurface::Thunks::set_popup_types[] {
    &wl_seat_interface_data,
    nullptr,
    &wl_surface_interface_data,
    nullptr,
    nullptr,
    nullptr};

struct wl_interface const* mw::ShellSurface::Thunks::set_maximized_types[] {
    &wl_output_interface_data};

struct wl_message const mw::ShellSurface::Thunks::request_messages[] {
    {"pong", "u", all_null_types},
    {"move", "ou", move_types},
    {"resize", "ouu", resize_types},
    {"set_toplevel", "", all_null_types},
    {"set_transient", "oiiu", set_transient_types},
    {"set_fullscreen", "uu?o", set_fullscreen_types},
    {"set_popup", "ouoiiu", set_popup_types},
    {"set_maximized", "?o", set_maximized_types},
    {"set_title", "s", all_null_types},
    {"set_class", "s", all_null_types}};

struct wl_message const mw::ShellSurface::Thunks::event_messages[] {
    {"ping", "u", all_null_types},
    {"configure", "uii", all_null_types},
    {"popup_done", "", all_null_types}};

void const* mw::ShellSurface::Thunks::request_vtable[] {
    (void*)Thunks::pong_thunk,
    (void*)Thunks::move_thunk,
    (void*)Thunks::resize_thunk,
    (void*)Thunks::set_toplevel_thunk,
    (void*)Thunks::set_transient_thunk,
    (void*)Thunks::set_fullscreen_thunk,
    (void*)Thunks::set_popup_thunk,
    (void*)Thunks::set_maximized_thunk,
    (void*)Thunks::set_title_thunk,
    (void*)Thunks::set_class_thunk};

mw::ShellSurface* mw::ShellSurface::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_shell_surface_interface_data, ShellSurface::Thunks::request_vtable))
    {
        return static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Surface

struct mw::Surface::Thunks
{
    static int const supported_version;

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::destroy()");
        }
    }

    static void attach_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* buffer, int32_t x, int32_t y)
    {
        std::optional<struct wl_resource*> buffer_resolved;
        if (buffer != nullptr)
        {
            buffer_resolved = {buffer};
        }
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->attach(buffer_resolved, x, y);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::attach()");
        }
    }

    static void damage_thunk(struct wl_client* client, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
    {
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->damage(x, y, width, height);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::damage()");
        }
    }

    static void frame_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t callback)
    {
        wl_resource* callback_resolved{
            wl_resource_create(client, &wl_callback_interface_data, wl_resource_get_version(resource), callback)};
        if (callback_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->frame(callback_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::frame()");
        }
    }

    static void set_opaque_region_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* region)
    {
        std::optional<struct wl_resource*> region_resolved;
        if (region != nullptr)
        {
            region_resolved = {region};
        }
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->set_opaque_region(region_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::set_opaque_region()");
        }
    }

    static void set_input_region_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* region)
    {
        std::optional<struct wl_resource*> region_resolved;
        if (region != nullptr)
        {
            region_resolved = {region};
        }
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->set_input_region(region_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::set_input_region()");
        }
    }

    static void commit_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->commit();
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::commit()");
        }
    }

    static void set_buffer_transform_thunk(struct wl_client* client, struct wl_resource* resource, int32_t transform)
    {
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->set_buffer_transform(transform);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::set_buffer_transform()");
        }
    }

    static void set_buffer_scale_thunk(struct wl_client* client, struct wl_resource* resource, int32_t scale)
    {
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->set_buffer_scale(scale);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::set_buffer_scale()");
        }
    }

    static void damage_buffer_thunk(struct wl_client* client, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
    {
        try
        {
            auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
            me->damage_buffer(x, y, width, height);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Surface::damage_buffer()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Surface*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* attach_types[];
    static struct wl_interface const* frame_types[];
    static struct wl_interface const* set_opaque_region_types[];
    static struct wl_interface const* set_input_region_types[];
    static struct wl_interface const* enter_types[];
    static struct wl_interface const* leave_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Surface::Thunks::supported_version = 4;

mw::Surface::Surface(struct wl_resource* resource, Version<4>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Surface::~Surface()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Surface::send_enter_event(struct wl_resource* output) const
{
    wl_resource_post_event(resource, Opcode::enter, output);
}

void mw::Surface::send_leave_event(struct wl_resource* output) const
{
    wl_resource_post_event(resource, Opcode::leave, output);
}

bool mw::Surface::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_surface_interface_data, Thunks::request_vtable);
}

uint32_t const mw::Surface::Error::invalid_scale;
uint32_t const mw::Surface::Error::invalid_transform;

struct wl_interface const* mw::Surface::Thunks::attach_types[] {
    &wl_buffer_interface_data,
    nullptr,
    nullptr};

struct wl_interface const* mw::Surface::Thunks::frame_types[] {
    &wl_callback_interface_data};

struct wl_interface const* mw::Surface::Thunks::set_opaque_region_types[] {
    &wl_region_interface_data};

struct wl_interface const* mw::Surface::Thunks::set_input_region_types[] {
    &wl_region_interface_data};

struct wl_interface const* mw::Surface::Thunks::enter_types[] {
    &wl_output_interface_data};

struct wl_interface const* mw::Surface::Thunks::leave_types[] {
    &wl_output_interface_data};

struct wl_message const mw::Surface::Thunks::request_messages[] {
    {"destroy", "", all_null_types},
    {"attach", "?oii", attach_types},
    {"damage", "iiii", all_null_types},
    {"frame", "n", frame_types},
    {"set_opaque_region", "?o", set_opaque_region_types},
    {"set_input_region", "?o", set_input_region_types},
    {"commit", "", all_null_types},
    {"set_buffer_transform", "2i", all_null_types},
    {"set_buffer_scale", "3i", all_null_types},
    {"damage_buffer", "4iiii", all_null_types}};

struct wl_message const mw::Surface::Thunks::event_messages[] {
    {"enter", "o", enter_types},
    {"leave", "o", leave_types}};

void const* mw::Surface::Thunks::request_vtable[] {
    (void*)Thunks::destroy_thunk,
    (void*)Thunks::attach_thunk,
    (void*)Thunks::damage_thunk,
    (void*)Thunks::frame_thunk,
    (void*)Thunks::set_opaque_region_thunk,
    (void*)Thunks::set_input_region_thunk,
    (void*)Thunks::commit_thunk,
    (void*)Thunks::set_buffer_transform_thunk,
    (void*)Thunks::set_buffer_scale_thunk,
    (void*)Thunks::damage_buffer_thunk};

mw::Surface* mw::Surface::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_surface_interface_data, Surface::Thunks::request_vtable))
    {
        return static_cast<Surface*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Seat

struct mw::Seat::Thunks
{
    static int const supported_version;

    static void get_pointer_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_pointer_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
            me->get_pointer(id_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Seat::get_pointer()");
        }
    }

    static void get_keyboard_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_keyboard_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
            me->get_keyboard(id_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Seat::get_keyboard()");
        }
    }

    static void get_touch_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_touch_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
            me->get_touch(id_resolved);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Seat::get_touch()");
        }
    }

    static void release_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
            me->release();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Seat::release()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Seat*>(wl_resource_get_user_data(resource));
    }

    static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)
    {
        auto me = static_cast<Seat::Global*>(data);
        auto resource = wl_resource_create(
            client,
            &wl_seat_interface_data,
            std::min((int)version, Thunks::supported_version),
            id);
        if (resource == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            me->bind(resource);
        }
        catch(...)
        {
            internal_error_processing_request(client, "Seat global bind");
        }
    }

    static struct wl_interface const* get_pointer_types[];
    static struct wl_interface const* get_keyboard_types[];
    static struct wl_interface const* get_touch_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Seat::Thunks::supported_version = 8;

mw::Seat::Seat(struct wl_resource* resource, Version<8>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Seat::~Seat()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Seat::send_capabilities_event(uint32_t capabilities) const
{
    wl_resource_post_event(resource, Opcode::capabilities, capabilities);
}

bool mw::Seat::version_supports_name()
{
    return wl_resource_get_version(resource) >= 2;
}

void mw::Seat::send_name_event_if_supported(std::string const& name) const
{
    if (wl_resource_get_version(resource) >= 2)
    {
        const char* name_resolved = name.c_str();
        wl_resource_post_event(resource, Opcode::name, name_resolved);
    }
}

void mw::Seat::send_name_event(std::string const& name) const
{
    if (wl_resource_get_version(resource) >= 2)
    {
        const char* name_resolved = name.c_str();
        wl_resource_post_event(resource, Opcode::name, name_resolved);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "name", 2);
    }
}

bool mw::Seat::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_seat_interface_data, Thunks::request_vtable);
}

uint32_t const mw::Seat::Capability::pointer;
uint32_t const mw::Seat::Capability::keyboard;
uint32_t const mw::Seat::Capability::touch;
uint32_t const mw::Seat::Error::missing_capability;

mw::Seat::Global::Global(wl_display* display, Version<8>)
    : wayland::Global{
          wl_global_create(
              display,
              &wl_seat_interface_data,
              Thunks::supported_version,
              this,
              &Thunks::bind_thunk)}
{
}

auto mw::Seat::Global::interface_name() const -> char const*
{
    return Seat::interface_name;
}

struct wl_interface const* mw::Seat::Thunks::get_pointer_types[] {
    &wl_pointer_interface_data};

struct wl_interface const* mw::Seat::Thunks::get_keyboard_types[] {
    &wl_keyboard_interface_data};

struct wl_interface const* mw::Seat::Thunks::get_touch_types[] {
    &wl_touch_interface_data};

struct wl_message const mw::Seat::Thunks::request_messages[] {
    {"get_pointer", "n", get_pointer_types},
    {"get_keyboard", "n", get_keyboard_types},
    {"get_touch", "n", get_touch_types},
    {"release", "5", all_null_types}};

struct wl_message const mw::Seat::Thunks::event_messages[] {
    {"capabilities", "u", all_null_types},
    {"name", "2s", all_null_types}};

void const* mw::Seat::Thunks::request_vtable[] {
    (void*)Thunks::get_pointer_thunk,
    (void*)Thunks::get_keyboard_thunk,
    (void*)Thunks::get_touch_thunk,
    (void*)Thunks::release_thunk};

mw::Seat* mw::Seat::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_seat_interface_data, Seat::Thunks::request_vtable))
    {
        return static_cast<Seat*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Pointer

struct mw::Pointer::Thunks
{
    static int const supported_version;

    static void set_cursor_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t serial, struct wl_resource* surface, int32_t hotspot_x, int32_t hotspot_y)
    {
        std::optional<struct wl_resource*> surface_resolved;
        if (surface != nullptr)
        {
            surface_resolved = {surface};
        }
        try
        {
            auto me = static_cast<Pointer*>(wl_resource_get_user_data(resource));
            me->set_cursor(serial, surface_resolved, hotspot_x, hotspot_y);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Pointer::set_cursor()");
        }
    }

    static void release_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Pointer*>(wl_resource_get_user_data(resource));
            me->release();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Pointer::release()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Pointer*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* set_cursor_types[];
    static struct wl_interface const* enter_types[];
    static struct wl_interface const* leave_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Pointer::Thunks::supported_version = 8;

mw::Pointer::Pointer(struct wl_resource* resource, Version<8>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Pointer::~Pointer()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Pointer::send_enter_event(uint32_t serial, struct wl_resource* surface, double surface_x, double surface_y) const
{
    wl_fixed_t surface_x_resolved{wl_fixed_from_double(surface_x)};
    wl_fixed_t surface_y_resolved{wl_fixed_from_double(surface_y)};
    wl_resource_post_event(resource, Opcode::enter, serial, surface, surface_x_resolved, surface_y_resolved);
}

void mw::Pointer::send_leave_event(uint32_t serial, struct wl_resource* surface) const
{
    wl_resource_post_event(resource, Opcode::leave, serial, surface);
}

void mw::Pointer::send_motion_event(uint32_t time, double surface_x, double surface_y) const
{
    wl_fixed_t surface_x_resolved{wl_fixed_from_double(surface_x)};
    wl_fixed_t surface_y_resolved{wl_fixed_from_double(surface_y)};
    wl_resource_post_event(resource, Opcode::motion, time, surface_x_resolved, surface_y_resolved);
}

void mw::Pointer::send_button_event(uint32_t serial, uint32_t time, uint32_t button, uint32_t state) const
{
    wl_resource_post_event(resource, Opcode::button, serial, time, button, state);
}

void mw::Pointer::send_axis_event(uint32_t time, uint32_t axis, double value) const
{
    wl_fixed_t value_resolved{wl_fixed_from_double(value)};
    wl_resource_post_event(resource, Opcode::axis, time, axis, value_resolved);
}

bool mw::Pointer::version_supports_frame()
{
    return wl_resource_get_version(resource) >= 5;
}

void mw::Pointer::send_frame_event_if_supported() const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::frame);
    }
}

void mw::Pointer::send_frame_event() const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::frame);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "frame", 5);
    }
}

bool mw::Pointer::version_supports_axis_source()
{
    return wl_resource_get_version(resource) >= 5;
}

void mw::Pointer::send_axis_source_event_if_supported(uint32_t axis_source) const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::axis_source, axis_source);
    }
}

void mw::Pointer::send_axis_source_event(uint32_t axis_source) const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::axis_source, axis_source);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "axis_source", 5);
    }
}

bool mw::Pointer::version_supports_axis_stop()
{
    return wl_resource_get_version(resource) >= 5;
}

void mw::Pointer::send_axis_stop_event_if_supported(uint32_t time, uint32_t axis) const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::axis_stop, time, axis);
    }
}

void mw::Pointer::send_axis_stop_event(uint32_t time, uint32_t axis) const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::axis_stop, time, axis);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "axis_stop", 5);
    }
}

bool mw::Pointer::version_supports_axis_discrete()
{
    return wl_resource_get_version(resource) >= 5;
}

void mw::Pointer::send_axis_discrete_event_if_supported(uint32_t axis, int32_t discrete) const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::axis_discrete, axis, discrete);
    }
}

void mw::Pointer::send_axis_discrete_event(uint32_t axis, int32_t discrete) const
{
    if (wl_resource_get_version(resource) >= 5)
    {
        wl_resource_post_event(resource, Opcode::axis_discrete, axis, discrete);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "axis_discrete", 5);
    }
}

bool mw::Pointer::version_supports_axis_value120()
{
    return wl_resource_get_version(resource) >= 8;
}

void mw::Pointer::send_axis_value120_event_if_supported(uint32_t axis, int32_t value120) const
{
    if (wl_resource_get_version(resource) >= 8)
    {
        wl_resource_post_event(resource, Opcode::axis_value120, axis, value120);
    }
}

void mw::Pointer::send_axis_value120_event(uint32_t axis, int32_t value120) const
{
    if (wl_resource_get_version(resource) >= 8)
    {
        wl_resource_post_event(resource, Opcode::axis_value120, axis, value120);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "axis_value120", 8);
    }
}

bool mw::Pointer::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_pointer_interface_data, Thunks::request_vtable);
}

uint32_t const mw::Pointer::Error::role;
uint32_t const mw::Pointer::ButtonState::released;
uint32_t const mw::Pointer::ButtonState::pressed;
uint32_t const mw::Pointer::Axis::vertical_scroll;
uint32_t const mw::Pointer::Axis::horizontal_scroll;
uint32_t const mw::Pointer::AxisSource::wheel;
uint32_t const mw::Pointer::AxisSource::finger;
uint32_t const mw::Pointer::AxisSource::continuous;
uint32_t const mw::Pointer::AxisSource::wheel_tilt;

struct wl_interface const* mw::Pointer::Thunks::set_cursor_types[] {
    nullptr,
    &wl_surface_interface_data,
    nullptr,
    nullptr};

struct wl_interface const* mw::Pointer::Thunks::enter_types[] {
    nullptr,
    &wl_surface_interface_data,
    nullptr,
    nullptr};

struct wl_interface const* mw::Pointer::Thunks::leave_types[] {
    nullptr,
    &wl_surface_interface_data};

struct wl_message const mw::Pointer::Thunks::request_messages[] {
    {"set_cursor", "u?oii", set_cursor_types},
    {"release", "3", all_null_types}};

struct wl_message const mw::Pointer::Thunks::event_messages[] {
    {"enter", "uoff", enter_types},
    {"leave", "uo", leave_types},
    {"motion", "uff", all_null_types},
    {"button", "uuuu", all_null_types},
    {"axis", "uuf", all_null_types},
    {"frame", "5", all_null_types},
    {"axis_source", "5u", all_null_types},
    {"axis_stop", "5uu", all_null_types},
    {"axis_discrete", "5ui", all_null_types},
    {"axis_value120", "8ui", all_null_types}};

void const* mw::Pointer::Thunks::request_vtable[] {
    (void*)Thunks::set_cursor_thunk,
    (void*)Thunks::release_thunk};

mw::Pointer* mw::Pointer::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_pointer_interface_data, Pointer::Thunks::request_vtable))
    {
        return static_cast<Pointer*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Keyboard

struct mw::Keyboard::Thunks
{
    static int const supported_version;

    static void release_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Keyboard*>(wl_resource_get_user_data(resource));
            me->release();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Keyboard::release()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Keyboard*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* enter_types[];
    static struct wl_interface const* leave_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Keyboard::Thunks::supported_version = 8;

mw::Keyboard::Keyboard(struct wl_resource* resource, Version<8>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Keyboard::~Keyboard()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Keyboard::send_keymap_event(uint32_t format, mir::Fd fd, uint32_t size) const
{
    int32_t fd_resolved{fd};
    wl_resource_post_event(resource, Opcode::keymap, format, fd_resolved, size);
}

void mw::Keyboard::send_enter_event(uint32_t serial, struct wl_resource* surface, struct wl_array* keys) const
{
    wl_resource_post_event(resource, Opcode::enter, serial, surface, keys);
}

void mw::Keyboard::send_leave_event(uint32_t serial, struct wl_resource* surface) const
{
    wl_resource_post_event(resource, Opcode::leave, serial, surface);
}

void mw::Keyboard::send_key_event(uint32_t serial, uint32_t time, uint32_t key, uint32_t state) const
{
    wl_resource_post_event(resource, Opcode::key, serial, time, key, state);
}

void mw::Keyboard::send_modifiers_event(uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) const
{
    wl_resource_post_event(resource, Opcode::modifiers, serial, mods_depressed, mods_latched, mods_locked, group);
}

bool mw::Keyboard::version_supports_repeat_info()
{
    return wl_resource_get_version(resource) >= 4;
}

void mw::Keyboard::send_repeat_info_event_if_supported(int32_t rate, int32_t delay) const
{
    if (wl_resource_get_version(resource) >= 4)
    {
        wl_resource_post_event(resource, Opcode::repeat_info, rate, delay);
    }
}

void mw::Keyboard::send_repeat_info_event(int32_t rate, int32_t delay) const
{
    if (wl_resource_get_version(resource) >= 4)
    {
        wl_resource_post_event(resource, Opcode::repeat_info, rate, delay);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "repeat_info", 4);
    }
}

bool mw::Keyboard::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_keyboard_interface_data, Thunks::request_vtable);
}

uint32_t const mw::Keyboard::KeymapFormat::no_keymap;
uint32_t const mw::Keyboard::KeymapFormat::xkb_v1;
uint32_t const mw::Keyboard::KeyState::released;
uint32_t const mw::Keyboard::KeyState::pressed;

struct wl_interface const* mw::Keyboard::Thunks::enter_types[] {
    nullptr,
    &wl_surface_interface_data,
    nullptr};

struct wl_interface const* mw::Keyboard::Thunks::leave_types[] {
    nullptr,
    &wl_surface_interface_data};

struct wl_message const mw::Keyboard::Thunks::request_messages[] {
    {"release", "3", all_null_types}};

struct wl_message const mw::Keyboard::Thunks::event_messages[] {
    {"keymap", "uhu", all_null_types},
    {"enter", "uoa", enter_types},
    {"leave", "uo", leave_types},
    {"key", "uuuu", all_null_types},
    {"modifiers", "uuuuu", all_null_types},
    {"repeat_info", "4ii", all_null_types}};

void const* mw::Keyboard::Thunks::request_vtable[] {
    (void*)Thunks::release_thunk};

mw::Keyboard* mw::Keyboard::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_keyboard_interface_data, Keyboard::Thunks::request_vtable))
    {
        return static_cast<Keyboard*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Touch

struct mw::Touch::Thunks
{
    static int const supported_version;

    static void release_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Touch*>(wl_resource_get_user_data(resource));
            me->release();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Touch::release()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Touch*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* down_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Touch::Thunks::supported_version = 8;

mw::Touch::Touch(struct wl_resource* resource, Version<8>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Touch::~Touch()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Touch::send_down_event(uint32_t serial, uint32_t time, struct wl_resource* surface, int32_t id, double x, double y) const
{
    wl_fixed_t x_resolved{wl_fixed_from_double(x)};
    wl_fixed_t y_resolved{wl_fixed_from_double(y)};
    wl_resource_post_event(resource, Opcode::down, serial, time, surface, id, x_resolved, y_resolved);
}

void mw::Touch::send_up_event(uint32_t serial, uint32_t time, int32_t id) const
{
    wl_resource_post_event(resource, Opcode::up, serial, time, id);
}

void mw::Touch::send_motion_event(uint32_t time, int32_t id, double x, double y) const
{
    wl_fixed_t x_resolved{wl_fixed_from_double(x)};
    wl_fixed_t y_resolved{wl_fixed_from_double(y)};
    wl_resource_post_event(resource, Opcode::motion, time, id, x_resolved, y_resolved);
}

void mw::Touch::send_frame_event() const
{
    wl_resource_post_event(resource, Opcode::frame);
}

void mw::Touch::send_cancel_event() const
{
    wl_resource_post_event(resource, Opcode::cancel);
}

bool mw::Touch::version_supports_shape()
{
    return wl_resource_get_version(resource) >= 6;
}

void mw::Touch::send_shape_event_if_supported(int32_t id, double major, double minor) const
{
    if (wl_resource_get_version(resource) >= 6)
    {
        wl_fixed_t major_resolved{wl_fixed_from_double(major)};
        wl_fixed_t minor_resolved{wl_fixed_from_double(minor)};
        wl_resource_post_event(resource, Opcode::shape, id, major_resolved, minor_resolved);
    }
}

void mw::Touch::send_shape_event(int32_t id, double major, double minor) const
{
    if (wl_resource_get_version(resource) >= 6)
    {
        wl_fixed_t major_resolved{wl_fixed_from_double(major)};
        wl_fixed_t minor_resolved{wl_fixed_from_double(minor)};
        wl_resource_post_event(resource, Opcode::shape, id, major_resolved, minor_resolved);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "shape", 6);
    }
}

bool mw::Touch::version_supports_orientation()
{
    return wl_resource_get_version(resource) >= 6;
}

void mw::Touch::send_orientation_event_if_supported(int32_t id, double orientation) const
{
    if (wl_resource_get_version(resource) >= 6)
    {
        wl_fixed_t orientation_resolved{wl_fixed_from_double(orientation)};
        wl_resource_post_event(resource, Opcode::orientation, id, orientation_resolved);
    }
}

void mw::Touch::send_orientation_event(int32_t id, double orientation) const
{
    if (wl_resource_get_version(resource) >= 6)
    {
        wl_fixed_t orientation_resolved{wl_fixed_from_double(orientation)};
        wl_resource_post_event(resource, Opcode::orientation, id, orientation_resolved);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "orientation", 6);
    }
}

bool mw::Touch::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_touch_interface_data, Thunks::request_vtable);
}

struct wl_interface const* mw::Touch::Thunks::down_types[] {
    nullptr,
    nullptr,
    &wl_surface_interface_data,
    nullptr,
    nullptr,
    nullptr};

struct wl_message const mw::Touch::Thunks::request_messages[] {
    {"release", "3", all_null_types}};

struct wl_message const mw::Touch::Thunks::event_messages[] {
    {"down", "uuoiff", down_types},
    {"up", "uui", all_null_types},
    {"motion", "uiff", all_null_types},
    {"frame", "", all_null_types},
    {"cancel", "", all_null_types},
    {"shape", "6iff", all_null_types},
    {"orientation", "6if", all_null_types}};

void const* mw::Touch::Thunks::request_vtable[] {
    (void*)Thunks::release_thunk};

mw::Touch* mw::Touch::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_touch_interface_data, Touch::Thunks::request_vtable))
    {
        return static_cast<Touch*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Output

struct mw::Output::Thunks
{
    static int const supported_version;

    static void release_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Output*>(wl_resource_get_user_data(resource));
            me->release();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Output::release()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Output*>(wl_resource_get_user_data(resource));
    }

    static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)
    {
        auto me = static_cast<Output::Global*>(data);
        auto resource = wl_resource_create(
            client,
            &wl_output_interface_data,
            std::min((int)version, Thunks::supported_version),
            id);
        if (resource == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            me->bind(resource);
        }
        catch(...)
        {
            internal_error_processing_request(client, "Output global bind");
        }
    }

    static struct wl_interface const* geometry_types[];
    static struct wl_message const request_messages[];
    static struct wl_message const event_messages[];
    static void const* request_vtable[];
};

int const mw::Output::Thunks::supported_version = 4;

mw::Output::Output(struct wl_resource* resource, Version<4>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Output::~Output()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

void mw::Output::send_geometry_event(int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, std::string const& make, std::string const& model, int32_t transform) const
{
    const char* make_resolved = make.c_str();
    const char* model_resolved = model.c_str();
    wl_resource_post_event(resource, Opcode::geometry, x, y, physical_width, physical_height, subpixel, make_resolved, model_resolved, transform);
}

void mw::Output::send_mode_event(uint32_t flags, int32_t width, int32_t height, int32_t refresh) const
{
    wl_resource_post_event(resource, Opcode::mode, flags, width, height, refresh);
}

bool mw::Output::version_supports_done()
{
    return wl_resource_get_version(resource) >= 2;
}

void mw::Output::send_done_event_if_supported() const
{
    if (wl_resource_get_version(resource) >= 2)
    {
        wl_resource_post_event(resource, Opcode::done);
    }
}

void mw::Output::send_done_event() const
{
    if (wl_resource_get_version(resource) >= 2)
    {
        wl_resource_post_event(resource, Opcode::done);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "done", 2);
    }
}

bool mw::Output::version_supports_scale()
{
    return wl_resource_get_version(resource) >= 2;
}

void mw::Output::send_scale_event_if_supported(int32_t factor) const
{
    if (wl_resource_get_version(resource) >= 2)
    {
        wl_resource_post_event(resource, Opcode::scale, factor);
    }
}

void mw::Output::send_scale_event(int32_t factor) const
{
    if (wl_resource_get_version(resource) >= 2)
    {
        wl_resource_post_event(resource, Opcode::scale, factor);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "scale", 2);
    }
}

bool mw::Output::version_supports_name()
{
    return wl_resource_get_version(resource) >= 4;
}

void mw::Output::send_name_event_if_supported(std::string const& name) const
{
    if (wl_resource_get_version(resource) >= 4)
    {
        const char* name_resolved = name.c_str();
        wl_resource_post_event(resource, Opcode::name, name_resolved);
    }
}

void mw::Output::send_name_event(std::string const& name) const
{
    if (wl_resource_get_version(resource) >= 4)
    {
        const char* name_resolved = name.c_str();
        wl_resource_post_event(resource, Opcode::name, name_resolved);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "name", 4);
    }
}

bool mw::Output::version_supports_description()
{
    return wl_resource_get_version(resource) >= 4;
}

void mw::Output::send_description_event_if_supported(std::string const& description) const
{
    if (wl_resource_get_version(resource) >= 4)
    {
        const char* description_resolved = description.c_str();
        wl_resource_post_event(resource, Opcode::description, description_resolved);
    }
}

void mw::Output::send_description_event(std::string const& description) const
{
    if (wl_resource_get_version(resource) >= 4)
    {
        const char* description_resolved = description.c_str();
        wl_resource_post_event(resource, Opcode::description, description_resolved);
    }
    else
    {
        tried_to_send_unsupported_event(client->raw_client(), resource, "description", 4);
    }
}

bool mw::Output::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_output_interface_data, Thunks::request_vtable);
}

uint32_t const mw::Output::Subpixel::unknown;
uint32_t const mw::Output::Subpixel::none;
uint32_t const mw::Output::Subpixel::horizontal_rgb;
uint32_t const mw::Output::Subpixel::horizontal_bgr;
uint32_t const mw::Output::Subpixel::vertical_rgb;
uint32_t const mw::Output::Subpixel::vertical_bgr;
uint32_t const mw::Output::Transform::normal;
uint32_t const mw::Output::Transform::_90;
uint32_t const mw::Output::Transform::_180;
uint32_t const mw::Output::Transform::_270;
uint32_t const mw::Output::Transform::flipped;
uint32_t const mw::Output::Transform::flipped_90;
uint32_t const mw::Output::Transform::flipped_180;
uint32_t const mw::Output::Transform::flipped_270;
uint32_t const mw::Output::Mode::current;
uint32_t const mw::Output::Mode::preferred;

mw::Output::Global::Global(wl_display* display, Version<4>)
    : wayland::Global{
          wl_global_create(
              display,
              &wl_output_interface_data,
              Thunks::supported_version,
              this,
              &Thunks::bind_thunk)}
{
}

auto mw::Output::Global::interface_name() const -> char const*
{
    return Output::interface_name;
}

struct wl_interface const* mw::Output::Thunks::geometry_types[] {
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    nullptr};

struct wl_message const mw::Output::Thunks::request_messages[] {
    {"release", "3", all_null_types}};

struct wl_message const mw::Output::Thunks::event_messages[] {
    {"geometry", "iiiiissi", geometry_types},
    {"mode", "uiii", all_null_types},
    {"done", "2", all_null_types},
    {"scale", "2i", all_null_types},
    {"name", "4s", all_null_types},
    {"description", "4s", all_null_types}};

void const* mw::Output::Thunks::request_vtable[] {
    (void*)Thunks::release_thunk};

mw::Output* mw::Output::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_output_interface_data, Output::Thunks::request_vtable))
    {
        return static_cast<Output*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Region

struct mw::Region::Thunks
{
    static int const supported_version;

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Region*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Region::destroy()");
        }
    }

    static void add_thunk(struct wl_client* client, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
    {
        try
        {
            auto me = static_cast<Region*>(wl_resource_get_user_data(resource));
            me->add(x, y, width, height);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Region::add()");
        }
    }

    static void subtract_thunk(struct wl_client* client, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
    {
        try
        {
            auto me = static_cast<Region*>(wl_resource_get_user_data(resource));
            me->subtract(x, y, width, height);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Region::subtract()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Region*>(wl_resource_get_user_data(resource));
    }

    static struct wl_message const request_messages[];
    static void const* request_vtable[];
};

int const mw::Region::Thunks::supported_version = 1;

mw::Region::Region(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Region::~Region()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

bool mw::Region::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_region_interface_data, Thunks::request_vtable);
}

struct wl_message const mw::Region::Thunks::request_messages[] {
    {"destroy", "", all_null_types},
    {"add", "iiii", all_null_types},
    {"subtract", "iiii", all_null_types}};

void const* mw::Region::Thunks::request_vtable[] {
    (void*)Thunks::destroy_thunk,
    (void*)Thunks::add_thunk,
    (void*)Thunks::subtract_thunk};

mw::Region* mw::Region::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_region_interface_data, Region::Thunks::request_vtable))
    {
        return static_cast<Region*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Subcompositor

struct mw::Subcompositor::Thunks
{
    static int const supported_version;

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Subcompositor*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subcompositor::destroy()");
        }
    }

    static void get_subsurface_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* surface, struct wl_resource* parent)
    {
        wl_resource* id_resolved{
            wl_resource_create(client, &wl_subsurface_interface_data, wl_resource_get_version(resource), id)};
        if (id_resolved == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            auto me = static_cast<Subcompositor*>(wl_resource_get_user_data(resource));
            me->get_subsurface(id_resolved, surface, parent);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subcompositor::get_subsurface()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Subcompositor*>(wl_resource_get_user_data(resource));
    }

    static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)
    {
        auto me = static_cast<Subcompositor::Global*>(data);
        auto resource = wl_resource_create(
            client,
            &wl_subcompositor_interface_data,
            std::min((int)version, Thunks::supported_version),
            id);
        if (resource == nullptr)
        {
            wl_client_post_no_memory(client);
            BOOST_THROW_EXCEPTION((std::bad_alloc{}));
        }
        try
        {
            me->bind(resource);
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subcompositor global bind");
        }
    }

    static struct wl_interface const* get_subsurface_types[];
    static struct wl_message const request_messages[];
    static void const* request_vtable[];
};

int const mw::Subcompositor::Thunks::supported_version = 1;

mw::Subcompositor::Subcompositor(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Subcompositor::~Subcompositor()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

bool mw::Subcompositor::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_subcompositor_interface_data, Thunks::request_vtable);
}

uint32_t const mw::Subcompositor::Error::bad_surface;

mw::Subcompositor::Global::Global(wl_display* display, Version<1>)
    : wayland::Global{
          wl_global_create(
              display,
              &wl_subcompositor_interface_data,
              Thunks::supported_version,
              this,
              &Thunks::bind_thunk)}
{
}

auto mw::Subcompositor::Global::interface_name() const -> char const*
{
    return Subcompositor::interface_name;
}

struct wl_interface const* mw::Subcompositor::Thunks::get_subsurface_types[] {
    &wl_subsurface_interface_data,
    &wl_surface_interface_data,
    &wl_surface_interface_data};

struct wl_message const mw::Subcompositor::Thunks::request_messages[] {
    {"destroy", "", all_null_types},
    {"get_subsurface", "noo", get_subsurface_types}};

void const* mw::Subcompositor::Thunks::request_vtable[] {
    (void*)Thunks::destroy_thunk,
    (void*)Thunks::get_subsurface_thunk};

mw::Subcompositor* mw::Subcompositor::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_subcompositor_interface_data, Subcompositor::Thunks::request_vtable))
    {
        return static_cast<Subcompositor*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

// Subsurface

struct mw::Subsurface::Thunks
{
    static int const supported_version;

    static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
            me->destroy();
            wl_resource_destroy(resource);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subsurface::destroy()");
        }
    }

    static void set_position_thunk(struct wl_client* client, struct wl_resource* resource, int32_t x, int32_t y)
    {
        try
        {
            auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
            me->set_position(x, y);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subsurface::set_position()");
        }
    }

    static void place_above_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* sibling)
    {
        try
        {
            auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
            me->place_above(sibling);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subsurface::place_above()");
        }
    }

    static void place_below_thunk(struct wl_client* client, struct wl_resource* resource, struct wl_resource* sibling)
    {
        try
        {
            auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
            me->place_below(sibling);
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subsurface::place_below()");
        }
    }

    static void set_sync_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
            me->set_sync();
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subsurface::set_sync()");
        }
    }

    static void set_desync_thunk(struct wl_client* client, struct wl_resource* resource)
    {
        try
        {
            auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
            me->set_desync();
        }
        catch(ProtocolError const& err)
        {
            wl_resource_post_error(err.resource(), err.code(), "%s", err.message());
        }
        catch(...)
        {
            internal_error_processing_request(client, "Subsurface::set_desync()");
        }
    }

    static void resource_destroyed_thunk(wl_resource* resource)
    {
        delete static_cast<Subsurface*>(wl_resource_get_user_data(resource));
    }

    static struct wl_interface const* place_above_types[];
    static struct wl_interface const* place_below_types[];
    static struct wl_message const request_messages[];
    static void const* request_vtable[];
};

int const mw::Subsurface::Thunks::supported_version = 1;

mw::Subsurface::Subsurface(struct wl_resource* resource, Version<1>)
    : Resource{resource}
{
    wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);
}

mw::Subsurface::~Subsurface()
{
    wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);
}

bool mw::Subsurface::is_instance(wl_resource* resource)
{
    return wl_resource_instance_of(resource, &wl_subsurface_interface_data, Thunks::request_vtable);
}

uint32_t const mw::Subsurface::Error::bad_surface;

struct wl_interface const* mw::Subsurface::Thunks::place_above_types[] {
    &wl_surface_interface_data};

struct wl_interface const* mw::Subsurface::Thunks::place_below_types[] {
    &wl_surface_interface_data};

struct wl_message const mw::Subsurface::Thunks::request_messages[] {
    {"destroy", "", all_null_types},
    {"set_position", "ii", all_null_types},
    {"place_above", "o", place_above_types},
    {"place_below", "o", place_below_types},
    {"set_sync", "", all_null_types},
    {"set_desync", "", all_null_types}};

void const* mw::Subsurface::Thunks::request_vtable[] {
    (void*)Thunks::destroy_thunk,
    (void*)Thunks::set_position_thunk,
    (void*)Thunks::place_above_thunk,
    (void*)Thunks::place_below_thunk,
    (void*)Thunks::set_sync_thunk,
    (void*)Thunks::set_desync_thunk};

mw::Subsurface* mw::Subsurface::from(struct wl_resource* resource)
{
    if (resource &&
        wl_resource_instance_of(resource, &wl_subsurface_interface_data, Subsurface::Thunks::request_vtable))
    {
        return static_cast<Subsurface*>(wl_resource_get_user_data(resource));
    }
    else
    {
        return nullptr;
    }
}

namespace mir
{
namespace wayland
{

struct wl_interface const wl_callback_interface_data {
    mw::Callback::interface_name,
    mw::Callback::Thunks::supported_version,
    0, nullptr,
    1, mw::Callback::Thunks::event_messages};

struct wl_interface const wl_compositor_interface_data {
    mw::Compositor::interface_name,
    mw::Compositor::Thunks::supported_version,
    2, mw::Compositor::Thunks::request_messages,
    0, nullptr};

struct wl_interface const wl_shm_pool_interface_data {
    mw::ShmPool::interface_name,
    mw::ShmPool::Thunks::supported_version,
    3, mw::ShmPool::Thunks::request_messages,
    0, nullptr};

struct wl_interface const wl_shm_interface_data {
    mw::Shm::interface_name,
    mw::Shm::Thunks::supported_version,
    1, mw::Shm::Thunks::request_messages,
    1, mw::Shm::Thunks::event_messages};

struct wl_interface const wl_buffer_interface_data {
    mw::Buffer::interface_name,
    mw::Buffer::Thunks::supported_version,
    1, mw::Buffer::Thunks::request_messages,
    1, mw::Buffer::Thunks::event_messages};

struct wl_interface const wl_data_offer_interface_data {
    mw::DataOffer::interface_name,
    mw::DataOffer::Thunks::supported_version,
    5, mw::DataOffer::Thunks::request_messages,
    3, mw::DataOffer::Thunks::event_messages};

struct wl_interface const wl_data_source_interface_data {
    mw::DataSource::interface_name,
    mw::DataSource::Thunks::supported_version,
    3, mw::DataSource::Thunks::request_messages,
    6, mw::DataSource::Thunks::event_messages};

struct wl_interface const wl_data_device_interface_data {
    mw::DataDevice::interface_name,
    mw::DataDevice::Thunks::supported_version,
    3, mw::DataDevice::Thunks::request_messages,
    6, mw::DataDevice::Thunks::event_messages};

struct wl_interface const wl_data_device_manager_interface_data {
    mw::DataDeviceManager::interface_name,
    mw::DataDeviceManager::Thunks::supported_version,
    2, mw::DataDeviceManager::Thunks::request_messages,
    0, nullptr};

struct wl_interface const wl_shell_interface_data {
    mw::Shell::interface_name,
    mw::Shell::Thunks::supported_version,
    1, mw::Shell::Thunks::request_messages,
    0, nullptr};

struct wl_interface const wl_shell_surface_interface_data {
    mw::ShellSurface::interface_name,
    mw::ShellSurface::Thunks::supported_version,
    10, mw::ShellSurface::Thunks::request_messages,
    3, mw::ShellSurface::Thunks::event_messages};

struct wl_interface const wl_surface_interface_data {
    mw::Surface::interface_name,
    mw::Surface::Thunks::supported_version,
    10, mw::Surface::Thunks::request_messages,
    2, mw::Surface::Thunks::event_messages};

struct wl_interface const wl_seat_interface_data {
    mw::Seat::interface_name,
    mw::Seat::Thunks::supported_version,
    4, mw::Seat::Thunks::request_messages,
    2, mw::Seat::Thunks::event_messages};

struct wl_interface const wl_pointer_interface_data {
    mw::Pointer::interface_name,
    mw::Pointer::Thunks::supported_version,
    2, mw::Pointer::Thunks::request_messages,
    10, mw::Pointer::Thunks::event_messages};

struct wl_interface const wl_keyboard_interface_data {
    mw::Keyboard::interface_name,
    mw::Keyboard::Thunks::supported_version,
    1, mw::Keyboard::Thunks::request_messages,
    6, mw::Keyboard::Thunks::event_messages};

struct wl_interface const wl_touch_interface_data {
    mw::Touch::interface_name,
    mw::Touch::Thunks::supported_version,
    1, mw::Touch::Thunks::request_messages,
    7, mw::Touch::Thunks::event_messages};

struct wl_interface const wl_output_interface_data {
    mw::Output::interface_name,
    mw::Output::Thunks::supported_version,
    1, mw::Output::Thunks::request_messages,
    6, mw::Output::Thunks::event_messages};

struct wl_interface const wl_region_interface_data {
    mw::Region::interface_name,
    mw::Region::Thunks::supported_version,
    3, mw::Region::Thunks::request_messages,
    0, nullptr};

struct wl_interface const wl_subcompositor_interface_data {
    mw::Subcompositor::interface_name,
    mw::Subcompositor::Thunks::supported_version,
    2, mw::Subcompositor::Thunks::request_messages,
    0, nullptr};

struct wl_interface const wl_subsurface_interface_data {
    mw::Subsurface::interface_name,
    mw::Subsurface::Thunks::supported_version,
    6, mw::Subsurface::Thunks::request_messages,
    0, nullptr};

}
}
