diff --git a/include/wayland/mir/wayland/client.h b/include/wayland/mir/wayland/client.h index e6d25f09c93..6ec91834be5 100644 --- a/include/wayland/mir/wayland/client.h +++ b/include/wayland/mir/wayland/client.h @@ -41,12 +41,6 @@ class Resource; class Client : public wayland::LifetimeTracker { public: - /// Returns the Client object for the given libwayland client - static auto from(wl_client const* client) -> Client&; - - /// The underlying Wayland client - virtual auto raw_client() const -> wl_client* = 0; - /// True if the client's destroy listener has fired. The client object continues to exist after this until all /// resources have been cleaned up. virtual auto is_being_destroyed() const -> bool = 0; @@ -54,7 +48,7 @@ class Client : public wayland::LifetimeTracker /// The Mir session associated with this client. Be careful when using this that it's actually the session you want. /// All clients have a session but the surfaces they create may get associated with additional sessions. /// - /// For example all surfaces from a single XWayland server are attached to a single Client with a single cleint + /// For example all surfaces from a single XWayland server are attached to a single Client with a single client /// session, but their scene::Surfaces are associated with multiple sessions created in the XWayland frontend for /// individual apps. virtual auto client_session() const -> std::shared_ptr = 0; @@ -72,14 +66,6 @@ class Client : public wayland::LifetimeTracker virtual void set_output_geometry_scale(float scale) = 0; virtual auto output_geometry_scale() -> float = 0; /// @} - -protected: - static void register_client(wl_client const* raw, std::shared_ptr const& shared); - static void unregister_client(wl_client const* raw); - -private: - friend Resource; - static auto shared_from(wl_client const* client) -> std::shared_ptr; }; } } diff --git a/include/wayland/mir/wayland/global.h b/include/wayland/mir/wayland/global.h deleted file mode 100644 index 50a2c984bfd..00000000000 --- a/include/wayland/mir/wayland/global.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GLOBAL_H_ -#define MIR_WAYLAND_GLOBAL_H_ - -struct wl_global; - -namespace mir -{ -namespace wayland -{ -class Global -{ -public: - template - struct Version - { - }; - - explicit Global(wl_global* global); - virtual ~Global(); - - Global(Global const&) = delete; - Global& operator=(Global const&) = delete; - - virtual auto interface_name() const -> char const* = 0; - - wl_global* const global; -}; -} -} - -#endif // MIR_WAYLAND_GLOBAL_H_ diff --git a/include/wayland/mir/wayland/protocol_error.h b/include/wayland/mir/wayland/protocol_error.h deleted file mode 100644 index a162d589a39..00000000000 --- a/include/wayland/mir/wayland/protocol_error.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_PROTOCOL_ERROR_H_ -#define MIR_WAYLAND_PROTOCOL_ERROR_H_ - -#include -#include -#include - -struct wl_resource; -struct wl_client; - -namespace mir -{ -namespace wayland -{ -/// For when the protocol does not provide an appropriate error code -uint32_t const generic_error_code = -1; - -/** - * An exception type representing a Wayland protocol error - * - * Throwing one of these from a request handler will result in the client - * being sent a \a code error on \a source, with the printf-style \a fmt string - * populated as the message.: - */ -class ProtocolError : public std::runtime_error -{ -public: - [[gnu::format (printf, 4, 5)]] // Format attribute counts the hidden this parameter - ProtocolError(wl_resource* source, uint32_t code, char const* fmt, ...); - - auto message() const -> char const*; - auto resource() const -> wl_resource*; - auto code() const -> uint32_t; -private: - std::string error_message; - wl_resource* const source; - uint32_t const error_code; -}; - -void internal_error_processing_request(wl_client* client, char const* method_name); -void tried_to_send_unsupported_event(wl_client* client, wl_resource* resource, char const* event, int required_version); -} -} - -#endif // MIR_WAYLAND_PROTOCOL_ERROR_H_ diff --git a/include/wayland/mir/wayland/resource.h b/include/wayland/mir/wayland/resource.h deleted file mode 100644 index d3d75be5c07..00000000000 --- a/include/wayland/mir/wayland/resource.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_RESOURCE_H_ -#define MIR_WAYLAND_RESOURCE_H_ - -#include "lifetime_tracker.h" - -struct wl_resource; -struct wl_client; - -namespace mir -{ -namespace wayland -{ -class Client; - -class Resource - : public virtual LifetimeTracker -{ -private: - std::shared_ptr const owned_client; - -public: - template - struct Version - { - }; - - Resource(wl_resource* resource); - virtual ~Resource(); - - wl_resource* const resource; - Client* const client; -}; -} -} - -#endif // MIR_WAYLAND_RESOURCE_H_ diff --git a/include/wayland/mir/wayland/wayland_base.h b/include/wayland/mir/wayland/wayland_base.h deleted file mode 100644 index 26770a6be13..00000000000 --- a/include/wayland/mir/wayland/wayland_base.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_BASE_H_ -#define MIR_WAYLAND_BASE_H_ - -#include "lifetime_tracker.h" -#include "weak.h" -#include "resource.h" -#include "global.h" -#include "protocol_error.h" - -#endif // MIR_WAYLAND_BASE_H_ diff --git a/include/wayland/mir/wayland/weak.h b/include/wayland/mir/wayland/weak.h deleted file mode 100644 index 1331c9fcfd1..00000000000 --- a/include/wayland/mir/wayland/weak.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_WEAK_H_ -#define MIR_WAYLAND_WEAK_H_ - -#include -#include - -namespace mir -{ -namespace wayland -{ -/// A weak handle to a Wayland resource (or any Destroyable) -/// May only be safely used from the Wayland thread -template -class Weak -{ -public: - Weak() - : resource{nullptr}, - destroyed_flag{nullptr} - { - } - - explicit Weak(T* resource) - : resource{resource}, - destroyed_flag{resource ? resource->destroyed_flag() : nullptr} - { - } - - Weak(Weak const&) = default; - auto operator=(Weak const&) -> Weak& = default; - - auto operator==(Weak const& other) const -> bool - { - if (*this && other) - { - return resource == other.resource; - } - else - { - return (!*this && !other); - } - } - - auto operator!=(Weak const& other) const -> bool - { - return !(*this == other); - } - - auto is(T const& other) const -> bool - { - if (*this) - { - return resource == &other; - } - else - { - return false; - } - } - - operator bool() const - { - return resource && !*destroyed_flag; - } - - auto value() const -> T& - { - if (!*this) - { - BOOST_THROW_EXCEPTION(std::logic_error( - std::string{"Attempted access of "} + - (resource ? "destroyed" : "null") + - " wayland::Weak<" + typeid(T).name() + ">")); - } - return *resource; - } - -private: - T* resource; - /// Is null if and only if resource is null - /// If the target bool is true then resource has been freed and should not be used - std::shared_ptr destroyed_flag; -}; - -template -auto make_weak(T* resource) -> Weak -{ - return Weak{resource}; -} - -template -auto as_nullable_ptr(Weak const& weak) -> T* -{ - return weak ? &weak.value() : nullptr; -} -} -} - -#endif // MIR_WAYLAND_WEAK_H_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e113fb5031a..02001862ac3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,7 +20,6 @@ add_subdirectory(platforms/) add_subdirectory(common/) add_subdirectory(platform/) -add_subdirectory(wayland/) add_subdirectory(server/) add_subdirectory(miral/) add_subdirectory(miroil/) diff --git a/src/server/frontend_wayland/CMakeLists.txt b/src/server/frontend_wayland/CMakeLists.txt index 5ad341bcd1b..3736f33e48b 100644 --- a/src/server/frontend_wayland/CMakeLists.txt +++ b/src/server/frontend_wayland/CMakeLists.txt @@ -12,7 +12,6 @@ set( wayland_default_configuration.cpp wayland_connector.cpp wayland_connector.h wl_client.cpp wl_client.h - wayland_executor.cpp wayland_executor.h wayland_surface_observer.cpp wayland_surface_observer.h wayland_input_dispatcher.cpp wayland_input_dispatcher.h wl_data_device_manager.cpp wl_data_device_manager.h @@ -128,13 +127,7 @@ target_link_libraries(mirfrontend-wayland mirplatform mircommon mircore + mirwayland_rs PRIVATE PkgConfig::GIOUnix ) - -if (MIR_ENABLE_RUST) - target_link_libraries(mirfrontend-wayland - PUBLIC - mirwayland_rs - ) -endif() diff --git a/src/server/frontend_wayland/data_control_v1.cpp b/src/server/frontend_wayland/data_control_v1.cpp index bc805a94e1a..af1f37f8808 100644 --- a/src/server/frontend_wayland/data_control_v1.cpp +++ b/src/server/frontend_wayland/data_control_v1.cpp @@ -18,6 +18,7 @@ #include "primary_selection_v1.h" #include "wl_data_source.h" #include "wl_seat.h" +#include "protocol_error.h" #include #include @@ -35,18 +36,10 @@ namespace frontend { class DataControlDeviceV1; -class DataControlSourceV1 : public wayland::DataControlSourceV1 +class DataControlSourceV1 : public wayland_rs::ExtDataControlSourceV1Impl { public: - DataControlSourceV1(struct wl_resource* id) : - wayland::DataControlSourceV1{id, Version<1>{}} - { - } - - static auto from(struct wl_resource* id) -> mf::DataControlSourceV1* - { - return dynamic_cast(wayland::DataControlSourceV1::from(id)); - } + DataControlSourceV1() = default; auto mime_types() const -> std::vector const& { @@ -64,18 +57,29 @@ class DataControlSourceV1 : public wayland::DataControlSourceV1 return false; } -private: - void offer(std::string const& mime_type) override + void offer(rust::String mime_type) override { if (finalized_) BOOST_THROW_EXCEPTION( - wayland::ProtocolError( - resource, - wayland::DataControlSourceV1::Error::invalid_offer, + wayland_rs::ProtocolError( + wayland_rs::ExtDataControlSourceV1Impl::Error::invalid_offer, "Cannot add MIME types after source is set")); - mime_types_.push_back(mime_type); + mime_types_.push_back(mime_type.c_str()); + } + + void destroy() override + { + for (auto const& clp : {state->clipboard, state->primary_clipboard}) + { + if (auto const dxs = std::dynamic_pointer_cast(clp->paste_source()); + dxs && dxs->source.is(*source)) + { + clp->clear_paste_source(); + } + } } +private: std::vector mime_types_; bool finalized_{false}; }; @@ -83,7 +87,7 @@ class DataControlSourceV1 : public wayland::DataControlSourceV1 class DataExchangeSource : public ms::DataExchangeSource { public: - DataExchangeSource(wayland::Weak source, WlSeat const* const seat) : + DataExchangeSource(std::shared_ptr const& source, std::shared_ptr const& seat) : source{source}, seat{seat} { @@ -91,17 +95,22 @@ class DataExchangeSource : public ms::DataExchangeSource auto mime_types() const -> std::vector const& override { - return source.value().mime_types(); + if (auto const locked = source.lock()) + return locked->mime_types(); + + return {}; } void initiate_send(std::string const& mime, Fd const& fd) override { - source.value().send_send_event(mime, fd); + if (auto const locked = source.lock()) + locked->send_send_event(mime, fd); } void cancelled() override { - source.value().send_cancelled_event(); + if (auto const locked = source.lock()) + locked->send_cancelled_event(); } void dnd_drop_performed() override @@ -122,8 +131,8 @@ class DataExchangeSource : public ms::DataExchangeSource { } - wayland::Weak const source; - WlSeat const* const seat; + std::weak_ptr const source; + std::weak_ptr const seat; }; struct DataControlStateV1 @@ -139,11 +148,11 @@ struct DataControlStateV1 std::shared_ptr const primary_clipboard; }; -class DataControlDeviceV1 : public wayland::DataControlDeviceV1 +class DataControlDeviceV1 : public wayland_rs::ExtDataControlDeviceV1Impl { public: // Impl seperated out because it depends on `DataControlOfferV1`, which itself depends on this class - DataControlDeviceV1(struct wl_resource* id, std::shared_ptr const& state, WlSeat const* seat); + DataControlDeviceV1(std::shared_ptr const& state, std::shared_ptr const& seat); ~DataControlDeviceV1() override { @@ -196,20 +205,20 @@ class DataControlDeviceV1 : public wayland::DataControlDeviceV1 } }; - auto data_exchange_source_from_source(struct wl_resource* data_control_source) + auto data_exchange_source_from_source(std::shared_ptr const& source) -> std::shared_ptr { - if (auto source = mf::DataControlSourceV1::from(data_control_source)) - { - if (!source) - return nullptr; + if (!source) + return nullptr; - if (!source->try_finalize()) - BOOST_THROW_EXCEPTION( - wayland::ProtocolError( - resource, wayland::DataControlDeviceV1::Error::used_source, "Source already used")); + auto const source_v1 = std::dynamic_pointer_cast(source); + if (!source_v1->try_finalize()) + { + BOOST_THROW_EXCEPTION( + wayland_rs::ProtocolError( + wayland_rs::ExtDataControlDeviceV1Impl::Error::used_source, "Source already used")); - return std::make_shared(wayland::Weak{source}, seat); + return std::make_shared(source_v1, seat.lock()); } if (auto wl_data_source = mf::WlDataSource::from(data_control_source)) @@ -225,12 +234,12 @@ class DataControlDeviceV1 : public wayland::DataControlDeviceV1 return nullptr; } - void set_selection(std::optional const& data_control_source) override + void set_selection(std::shared_ptr const& source, bool _has_source) override { - if (data_control_source) + if (source) { auto data_exchange_source = data_exchange_source_from_source(*data_control_source); - if (!data_control_source) + if (!data_exchange_source) { mir::log_warning("Attempt to call `set_selection` with a null source or an unhandled source type"); return; @@ -245,11 +254,11 @@ class DataControlDeviceV1 : public wayland::DataControlDeviceV1 } } - void set_primary_selection(std::optional const& data_control_source) override + void set_primary_selection(std::shared_ptr const& source, bool _has_source) override { - if (data_control_source) + if (source) { - auto data_exchange_source = data_exchange_source_from_source(*data_control_source); + auto data_exchange_source = data_exchange_source_from_source(*source); if (!data_control_source) { mir::log_warning( @@ -270,91 +279,62 @@ class DataControlDeviceV1 : public wayland::DataControlDeviceV1 std::shared_ptr const shared_state; - WlSeat const* const seat; + std::weak_ptr const seat; std::shared_ptr const clipboard_observer; std::shared_ptr const primary_clipboard_observer; std::shared_ptr our_source; std::shared_ptr our_primary_source; }; -struct DataControlOfferV1 : public wayland::DataControlOfferV1 +struct DataControlOfferV1 : public wayland_rs::ExtDataControlOfferV1Impl { DataControlOfferV1( - wayland::Weak parent, std::vector const& mime_types, bool is_primary) : - wayland::DataControlOfferV1{parent.value()}, + mf::DataControlDeviceV1* parent, std::vector const& mime_types, bool is_primary) : parent{parent}, mime_types_{mime_types}, is_primary{is_primary} { - parent.value().send_data_offer_event(resource); - for (auto const& mime : mime_types) + } + + auto associate(rust::Box instance) -> void override + { + ExtDataControlOfferV1Impl::associate(std::move(instance)); + parent->send_data_offer_event(get_box()); + for (auto const& mime : mime_types_) { send_offer_event(mime); } } - void receive(std::string const& mime, mir::Fd fd) override + void receive(rust::String mime, int fd) override { - parent.value().receive_from_current_source(mime, fd, is_primary); + parent->receive_from_current_source(mime.c_str(), mir::Fd{fd}, is_primary); } - wayland::Weak const parent; + DataControlDeviceV1* parent; std::vector const mime_types_; bool const is_primary; }; -class DataControlManagerV1 : public wayland::DataControlManagerV1::Global +class DataControlManagerV1 : public wayland_rs::ExtDataControlManagerV1Impl { public: DataControlManagerV1( - struct wl_display* display, std::shared_ptr const& clipboard, std::shared_ptr const& primary_clipboard) : - wayland::DataControlManagerV1::Global(display, Version<1>{}), state{std::make_shared(clipboard, primary_clipboard)} { } -private: - class Instance : public wayland::DataControlManagerV1 + auto create_data_source() -> std::shared_ptr override { - public: - Instance(struct wl_resource* id, std::shared_ptr const& state) : - wayland::DataControlManagerV1(id, Version<1>{}), - state{state} - { - } - - private: - void create_data_source(struct wl_resource* id) override - { - auto const source = new DataControlSourceV1{id}; - - source->add_destroy_listener( - [state=state, source] - { - for (auto const& clp : {state->clipboard, state->primary_clipboard}) - { - if (auto const dxs = std::dynamic_pointer_cast(clp->paste_source()); - dxs && dxs->source.is(*source)) - { - clp->clear_paste_source(); - } - } - }); - } - - void get_data_device(struct wl_resource* id, struct wl_resource* seat) override - { - new DataControlDeviceV1(id, state, WlSeat::from(seat)); - } - - std::shared_ptr const state; - }; + auto const source = std::make_shared(); + return source; + } - void bind(wl_resource* id) override + auto get_data_device(std::shared_ptr const& seat) -> std::shared_ptr override { - new Instance{id, state}; + return std::make_shared(state, seat); } std::shared_ptr const state; @@ -363,8 +343,7 @@ class DataControlManagerV1 : public wayland::DataControlManagerV1::Global } mf::DataControlDeviceV1::DataControlDeviceV1( - struct wl_resource* id, std::shared_ptr const& state, WlSeat const* seat) : - wayland::DataControlDeviceV1(id, Version<1>{}), + std::shared_ptr const& state, std::shared_ptr const& seat) : shared_state{state}, seat{seat}, clipboard_observer{std::make_shared([this](auto source) { on_clipboard_set(source, false); })}, @@ -381,7 +360,7 @@ void mf::DataControlDeviceV1::on_clipboard_set(std::shared_ptr(source)) { // If the notification comes from a different seat, ignore it - if (data_exchange_source->seat != this->seat) + if (data_exchange_source->seat.lock() != this->seat.lock()) return; } @@ -390,26 +369,25 @@ void mf::DataControlDeviceV1::on_clipboard_set(std::shared_ptrmime_types(), is_primary); + auto new_offer = std::make_shared(this, source->mime_types(), is_primary); // No need to lock, we already lock at the start of `set_selection` and `set_primary_selection` if (is_primary) - send_primary_selection_event({new_offer->resource}); + send_primary_selection_event(new_offer, true); else - send_selection_event({new_offer->resource}); + send_selection_event(new_offer, true); } else { if (is_primary) - send_primary_selection_event({}); + send_primary_selection_event(nullptr, false); else - send_selection_event({}); + send_selection_event(nullptr, false); } } auto mf::create_data_control_manager_v1( - struct wl_display* display, std::shared_ptr const& clipboard, - std::shared_ptr const& primary_clipboard) -> std::shared_ptr + std::shared_ptr const& primary_clipboard) -> std::shared_ptr { - return std::make_shared(display, clipboard, primary_clipboard); + return std::make_shared(clipboard, primary_clipboard); } diff --git a/src/server/frontend_wayland/data_control_v1.h b/src/server/frontend_wayland/data_control_v1.h index 5f8b8c5d1d4..f1ba12b4dec 100644 --- a/src/server/frontend_wayland/data_control_v1.h +++ b/src/server/frontend_wayland/data_control_v1.h @@ -18,7 +18,7 @@ #ifndef MIR_SERVER_FRONTEND_DATA_CONTROL_V1_H_ #define MIR_SERVER_FRONTEND_DATA_CONTROL_V1_H_ -#include "ext-data-control-v1_wrapper.h" +#include "wayland_rs/wayland_rs_cpp/include/ext_data_control_v1.h" namespace mir { @@ -29,9 +29,8 @@ class Clipboard; namespace frontend { auto create_data_control_manager_v1( - struct wl_display* display, std::shared_ptr const& clipboard, - std::shared_ptr const& primary_clipboard) -> std::shared_ptr; + std::shared_ptr const& primary_clipboard) -> std::shared_ptr; } } diff --git a/src/server/frontend_wayland/input_trigger_registration_v1.cpp b/src/server/frontend_wayland/input_trigger_registration_v1.cpp index 1c448be1017..c1a11141fa8 100644 --- a/src/server/frontend_wayland/input_trigger_registration_v1.cpp +++ b/src/server/frontend_wayland/input_trigger_registration_v1.cpp @@ -30,7 +30,7 @@ #include namespace mf = mir::frontend; -namespace mw = mir::wayland; +namespace mw = mir::wayland_rs; using Trigger = mf::InputTriggerRegistry::Trigger; using ActionGroup = mf::InputTriggerRegistry::ActionGroup; @@ -76,10 +76,11 @@ class InputTriggerModifiers MirInputEventModifiers const allowed; }; -class KeyboardTrigger : public Trigger, public mw::InputTriggerV1 +class KeyboardTrigger : public Trigger, public mw::ExtInputTriggerV1Impl { public: KeyboardTrigger( + rust::Box client, InputTriggerModifiers modifiers, std::shared_ptr const& keyboard_state_tracker, struct wl_resource* id); @@ -214,8 +215,7 @@ class mf::KeyboardCodeTrigger : public KeyboardTrigger mf::KeyboardSymTrigger::KeyboardSymTrigger( InputTriggerModifiers modifiers, uint32_t keysym, - std::shared_ptr const& keyboard_state_tracker, - struct wl_resource* id) : + std::shared_ptr const& keyboard_state_tracker) : KeyboardTrigger{modifiers, keyboard_state_tracker, id}, keysym{keysym} { @@ -342,7 +342,7 @@ auto InputTriggerModifiers::from_protocol(uint32_t protocol_mods) -> InputTrigge auto InputTriggerModifiers::from_protocol(uint32_t protocol_mods, bool shift_adjustment) -> InputTriggerModifiers { - using PM = mw::InputTriggerRegistrationManagerV1::Modifiers; + using PM = mw::ExtInputTriggerRegistrationManagerV1Impl::Modifiers; if (protocol_mods == 0 && !shift_adjustment) return InputTriggerModifiers{mir_input_event_modifier_none, mir_input_event_modifier_none}; @@ -454,31 +454,22 @@ bool InputTriggerModifiers::event_modifiers_are_superset(InputTriggerModifiers m } KeyboardTrigger::KeyboardTrigger( + rust::Box client, InputTriggerModifiers modifiers, - std::shared_ptr const& keyboard_state_tracker, - struct wl_resource* id) : - InputTriggerV1{id, Version<1>{}}, + std::shared_ptr const& keyboard_state_tracker) : + ExtInputTriggerV1Impl(std::move(client)), modifiers{modifiers}, keyboard_state_tracker{keyboard_state_tracker} { } -auto KeyboardTrigger::from(struct wl_resource* resource) -> KeyboardTrigger* -{ - if (auto* input_trigger = mw::InputTriggerV1::from(resource)) - return dynamic_cast(input_trigger); - - mir::log_warning("Non-mw::InputTriggerV1 resource passed to KeyboardTrigger::from"); - return nullptr; -} - -class InputTriggerActionControlV1 : public mw::InputTriggerActionControlV1 +class InputTriggerActionControlV1 : public mw::ExtInputTriggerActionControlV1Impl { public: - InputTriggerActionControlV1(std::shared_ptr const& action_group, struct wl_resource* id); + InputTriggerActionControlV1(std::shared_ptr const& action_group, rust::Box client); - void add_input_trigger_event(struct wl_resource* trigger) override; - void drop_input_trigger_event(struct wl_resource* trigger) override; + auto add_input_trigger_event(mir::wayland_rs::Weak const& trigger) -> void override; + auto drop_input_trigger_event(mir::wayland_rs::Weak const& trigger) -> void override; void cancel() override; void destroy() override; @@ -488,22 +479,25 @@ class InputTriggerActionControlV1 : public mw::InputTriggerActionControlV1 }; InputTriggerActionControlV1::InputTriggerActionControlV1( - std::shared_ptr const& action_group, struct wl_resource* id) : - mw::InputTriggerActionControlV1{id, Version<1>{}}, + std::shared_ptr const& action_group, rust::Box client) : + ExtInputTriggerActionControlV1Impl(std::move(client)), action_group{action_group} { } -void InputTriggerActionControlV1::add_input_trigger_event(struct wl_resource* trigger) +void InputTriggerActionControlV1::add_input_trigger_event(mw::Weak const& trigger) { - if (auto* keyboard_trigger = KeyboardTrigger::from(trigger)) + trigger.with_value([&](auto& trigger) { - keyboard_trigger->associate_with_action_group(action_group); - } + if (auto* keyboard_trigger = KeyboardTrigger::from(trigger)) + { + keyboard_trigger->associate_with_action_group(action_group); + } - mir::log_warning( - "input_trigger_action_control_v1.add_input_trigger_event: Unsupported trigger type for resource %p", - (void*)trigger); + mir::log_warning( + "input_trigger_action_control_v1.add_input_trigger_event: Unsupported trigger type for resource %d", + trigger.object_id()); + }); } void InputTriggerActionControlV1::drop_input_trigger_event(struct wl_resource* trigger) @@ -527,55 +521,24 @@ void InputTriggerActionControlV1::destroy() { } -class InputTriggerRegistrationManagerV1 : public mw::InputTriggerRegistrationManagerV1::Global +class InputTriggerRegistrationManagerV1 : public mw::ExtInputTriggerRegistrationManagerV1Impl { public: InputTriggerRegistrationManagerV1( - wl_display* display, + rust::Box client, std::shared_ptr const& action_group_manager, std::shared_ptr const& input_trigger_registry, std::shared_ptr const& keyboard_state_tracker) : - Global{display, Version<1>{}}, + ExtInputTriggerRegistrationManagerV1Impl(std::move(client)), action_group_manager{action_group_manager}, input_trigger_registry{input_trigger_registry}, keyboard_state_tracker{keyboard_state_tracker} { } - class Instance : public mw::InputTriggerRegistrationManagerV1 - { - public: - Instance( - wl_resource* new_ext_input_trigger_registration_manager_v1, - std::shared_ptr const& action_group_manager, - std::shared_ptr const& input_trigger_registry, - std::shared_ptr const& keyboard_state_tracker) : - mw::InputTriggerRegistrationManagerV1{new_ext_input_trigger_registration_manager_v1, Version<1>{}}, - action_group_manager{action_group_manager}, - input_trigger_registry{input_trigger_registry}, - keyboard_state_tracker{keyboard_state_tracker} - { - send_capabilities_event(Capability::keyboard); - } - - void register_keyboard_sym_trigger(uint32_t modifiers, uint32_t keysym, struct wl_resource* id) override; - void register_keyboard_code_trigger(uint32_t modifiers, uint32_t keycode, struct wl_resource* id) override; - void get_action_control(std::string const& name, struct wl_resource* id) override; - - private: - std::shared_ptr const action_group_manager; - std::shared_ptr const input_trigger_registry; - std::shared_ptr const keyboard_state_tracker; - }; - - void bind(wl_resource* new_ext_input_trigger_registration_manager_v1) override - { - new Instance{ - new_ext_input_trigger_registration_manager_v1, - action_group_manager, - input_trigger_registry, - keyboard_state_tracker}; - } + auto register_keyboard_sym_trigger(uint32_t modifiers, uint32_t keysym) -> std::shared_ptr override; + auto register_keyboard_code_trigger(uint32_t modifiers, uint32_t keycode) -> std::shared_ptr override; + auto get_action_control(rust::String name) -> std::shared_ptr override; private: std::shared_ptr const action_group_manager; @@ -584,7 +547,7 @@ class InputTriggerRegistrationManagerV1 : public mw::InputTriggerRegistrationMan }; // TODO: Store the description string -void InputTriggerRegistrationManagerV1::Instance::get_action_control(std::string const&, struct wl_resource* id) +auto InputTriggerRegistrationManagerV1::get_action_control(rust::String) -> std::shared_ptr { auto const [token, action_group] = action_group_manager->create_new_action_group(); auto const action_control = new InputTriggerActionControlV1{action_group, id}; @@ -644,12 +607,12 @@ void InputTriggerRegistrationManagerV1::Instance::register_keyboard_code_trigger } auto mf::create_input_trigger_registration_manager_v1( - wl_display* display, + rust::Box client, std::shared_ptr const& action_group_manager, std::shared_ptr const& input_trigger_registry, std::shared_ptr const& keyboard_state_tracker) - -> std::shared_ptr + -> std::shared_ptr { return std::make_shared( - display, action_group_manager, input_trigger_registry, keyboard_state_tracker); + std::move(client), action_group_manager, input_trigger_registry, keyboard_state_tracker); } diff --git a/src/server/frontend_wayland/input_trigger_registration_v1.h b/src/server/frontend_wayland/input_trigger_registration_v1.h index 46362a45f0b..3f93c924bdd 100644 --- a/src/server/frontend_wayland/input_trigger_registration_v1.h +++ b/src/server/frontend_wayland/input_trigger_registration_v1.h @@ -17,8 +17,8 @@ #ifndef MIR_SERVER_FRONTEND_INPUT_TRIGGER_REGISTRATION_V1_H_ #define MIR_SERVER_FRONTEND_INPUT_TRIGGER_REGISTRATION_V1_H_ -#include "ext-input-trigger-registration-v1_wrapper.h" #include "input_trigger_registry.h" +#include "wayland_rs/wayland_rs_cpp/include/ext_input_trigger_registration_v1.h" namespace mir { @@ -27,11 +27,11 @@ namespace frontend class KeyboardStateTracker; auto create_input_trigger_registration_manager_v1( - wl_display* display, + rust::Box client, std::shared_ptr const& action_group_manager, std::shared_ptr const& input_trigger_registry, std::shared_ptr const& keyboard_state_tracker) - -> std::shared_ptr; + -> std::shared_ptr; } } #endif diff --git a/src/server/frontend_wayland/input_trigger_registry.cpp b/src/server/frontend_wayland/input_trigger_registry.cpp index a979bb724f1..a2d6edfc1a3 100644 --- a/src/server/frontend_wayland/input_trigger_registry.cpp +++ b/src/server/frontend_wayland/input_trigger_registry.cpp @@ -57,16 +57,16 @@ auto mf::RecentTokens::contains(std::string_view token) const -> bool template void iterate_and_erase_expired( - std::vector>& vec, auto&& callback) + std::vector>& vec, auto&& callback) { std::erase_if( vec, [&](auto& action) { - if (!action) + if (action.expired()) return true; // Erase - callback(action.value()); + callback(action); return false; // Don't erase }); } @@ -76,7 +76,7 @@ mf::InputTriggerRegistry::InputTriggerRegistry() = default; bool mf::InputTriggerRegistry::register_trigger(Trigger* trigger) { // Housekeeping - std::erase_if(triggers, [](auto const& weak_trigger) { return !weak_trigger; }); + std::erase_if(triggers, [](auto const& weak_trigger) { return weak_trigger.expired(); }); auto const already_registered = sr::any_of( triggers, [trigger](auto const& other_trigger) { return trigger->is_same_trigger(&other_trigger.value()); }); diff --git a/src/server/frontend_wayland/input_trigger_registry.h b/src/server/frontend_wayland/input_trigger_registry.h index 371a2513423..e0f42c0688a 100644 --- a/src/server/frontend_wayland/input_trigger_registry.h +++ b/src/server/frontend_wayland/input_trigger_registry.h @@ -21,8 +21,7 @@ #include #include #include -#include -#include +#include "lifetime_tracker.h" #include #include @@ -74,7 +73,7 @@ class InputTriggerRegistry bool any_trigger_handled(MirEvent const& event); private: - std::vector> triggers; + std::vector> triggers; }; class InputTriggerRegistry::ActivationToken @@ -91,7 +90,7 @@ class InputTriggerRegistry::ActivationToken }; // Version-agnostic interface -class InputTriggerRegistry::Action : public virtual wayland::LifetimeTracker +class InputTriggerRegistry::Action : public virtual wayland_rs::LifetimeTracker { public: Action() = default; @@ -118,7 +117,7 @@ class InputTriggerRegistry::ActionGroup ActionGroup(ActionGroup&&) = delete; auto operator=(ActionGroup&&) -> ActionGroup& = delete; - void add(wayland::Weak action); + void add(std::weak_ptr action); void send_end(MirEvent const& event); void send_begin(MirEvent const& event); void cancel(); @@ -127,7 +126,7 @@ class InputTriggerRegistry::ActionGroup private: std::function const on_destroy{}; std::shared_ptr token_authority; - std::vector> actions; + std::vector> actions; std::optional activation_token; bool cancelled{false}; }; @@ -135,7 +134,7 @@ class InputTriggerRegistry::ActionGroup class InputTriggerRegistry::ActionGroupManager { public: - ActionGroupManager(std::shared_ptr const& token_authority, Executor& wayland_executor); + ActionGroupManager(std::shared_ptr const& token_authority); auto create_new_action_group() -> std::pair>; @@ -151,7 +150,7 @@ class InputTriggerRegistry::ActionGroupManager Executor& wayland_executor; }; -class InputTriggerRegistry::Trigger: public virtual wayland::LifetimeTracker +class InputTriggerRegistry::Trigger: public virtual wayland_rs::LifetimeTracker { public: enum class EventOutcome diff --git a/src/server/frontend_wayland/output_manager.cpp b/src/server/frontend_wayland/output_manager.cpp index ca32afa63e7..8032b6e71d0 100644 --- a/src/server/frontend_wayland/output_manager.cpp +++ b/src/server/frontend_wayland/output_manager.cpp @@ -15,7 +15,6 @@ */ #include "output_manager.h" -#include "wayland_executor.h" #include #include @@ -230,9 +229,8 @@ void mf::OutputGlobal::instance_destroyed(OutputInstance* instance) class mf::OutputManager::DisplayConfigObserver: public graphics::NullDisplayConfigurationObserver { public: - DisplayConfigObserver(OutputManager& manager, std::shared_ptr const& executor) - : manager{manager}, - executor{executor} + DisplayConfigObserver(OutputManager& manager) + : manager{manager} { } @@ -252,14 +250,11 @@ class mf::OutputManager::DisplayConfigObserver: public graphics::NullDisplayConf }; mf::OutputManager::OutputManager( - wl_display* display, - std::shared_ptr const& executor, std::shared_ptr> const& registrar) - : display{display}, - registrar{registrar}, - display_config_observer{std::make_shared(*this, executor)} + : registrar{registrar}, + display_config_observer{std::make_shared(*this)} { - registrar->register_interest(display_config_observer, *executor); + registrar->register_interest(display_config_observer); } mf::OutputManager::~OutputManager() diff --git a/src/server/frontend_wayland/output_manager.h b/src/server/frontend_wayland/output_manager.h index b65d86403f7..8303ae2dbf4 100644 --- a/src/server/frontend_wayland/output_manager.h +++ b/src/server/frontend_wayland/output_manager.h @@ -105,9 +105,7 @@ class OutputManagerListener class OutputManager { public: - OutputManager( - wl_display* display, - std::shared_ptr const& executor, + explicit OutputManager( std::shared_ptr> const& registrar); ~OutputManager(); @@ -127,7 +125,6 @@ class OutputManager struct DisplayConfigObserver; - wl_display* const display; std::shared_ptr> const registrar; std::shared_ptr const display_config_observer; std::unordered_map> outputs; diff --git a/src/server/frontend_wayland/shm.cpp b/src/server/frontend_wayland/shm.cpp index e79d456f4c3..47aaef16d2d 100644 --- a/src/server/frontend_wayland/shm.cpp +++ b/src/server/frontend_wayland/shm.cpp @@ -18,31 +18,27 @@ #include #include "../shm_backing.h" #include -#include -#include #include #include -#include "wayland_wrapper.h" #include #include -#include + +#include "protocol_error.h" +#include "wayland_rs/src/ffi.rs.h" namespace mf = mir::frontend; namespace mg = mir::graphics; namespace mrs = mir::renderer::software; mf::ShmBuffer::ShmBuffer( - struct wl_resource* resource, - std::shared_ptr wayland_executor, + rust::Box client, std::shared_ptr data, geometry::Size size, geometry::Stride stride, graphics::DRMFormat format) - : Buffer{resource, Version<1>{}}, - weak_me{wayland::make_weak(this)}, - wayland_executor{std::move(wayland_executor)}, + : WlBufferImpl(std::move(client)), data_{std::move(data)}, size_{std::move(size)}, stride_{stride}, @@ -56,8 +52,7 @@ class ErrorNotifyingRWMappableBuffer : public mrs::RWMappable { public: ErrorNotifyingRWMappableBuffer( - mir::wayland::Weak buffer, - std::shared_ptr wayland_executor, + std::shared_ptr const& buffer, std::shared_ptr data, mir::geometry::Size size, mir::geometry::Stride stride, @@ -72,8 +67,7 @@ class ErrorNotifyingRWMappableBuffer : public mrs::RWMappable void notify_access_error() const; private: - mir::wayland::Weak const weak_buffer; - std::shared_ptr const wayland_executor; + std::weak_ptr buffer; std::shared_ptr const data; mir::geometry::Size const size_; mir::geometry::Stride const stride_; @@ -131,14 +125,12 @@ class ErrorNotifyingMapping : public mir::renderer::software::Mapping }; ErrorNotifyingRWMappableBuffer::ErrorNotifyingRWMappableBuffer( - mir::wayland::Weak buffer, - std::shared_ptr wayland_executor, + std::shared_ptr const& buffer, std::shared_ptr data, mir::geometry::Size size, mir::geometry::Stride stride, MirPixelFormat format) - : weak_buffer{buffer}, - wayland_executor{std::move(wayland_executor)}, + : buffer{buffer}, data{std::move(data)}, size_{std::move(size)}, stride_{stride}, @@ -148,24 +140,19 @@ ErrorNotifyingRWMappableBuffer::ErrorNotifyingRWMappableBuffer( void ErrorNotifyingRWMappableBuffer::notify_access_error() const { - wayland_executor->spawn( - [buffer = weak_buffer]() - { - if (buffer) - { - wl_resource_post_error( - buffer.value().resource, - mir::wayland::Shm::Error::invalid_fd, - "Error accessing SHM buffer"); - } - else - { - mir::log( - mir::logging::Severity::warning, - "Client SHM Buffer", - "Client submitted invalid SHM buffer; rendering will be incomplete"); - } - }); + if (auto const locked = buffer.lock()) + { + locked->post_error( + mir::wayland_rs::WlShmImpl::Error::invalid_fd, + "Error accessing SHM buffer"); + } + else + { + mir::log( + mir::logging::Severity::warning, + "Client SHM Buffer", + "Client submitted invalid SHM buffer; rendering will be incomplete"); + } } auto ErrorNotifyingRWMappableBuffer::size() const -> mir::geometry::Size @@ -197,30 +184,18 @@ auto ErrorNotifyingRWMappableBuffer::map_writeable() -> std::unique_ptr std::shared_ptr { return std::make_shared( - wayland::make_weak(this), - wayland_executor, + shared_from_this(), data_, size_, stride_, format_.as_mir_format().value()); } -auto mf::ShmBuffer::from(wl_resource* resource) -> ShmBuffer* -{ - if (auto buffer = wayland::Buffer::from(resource)) - { - return dynamic_cast(buffer); - } - return nullptr; -} - mf::ShmPool::ShmPool( - struct wl_resource* resource, - std::shared_ptr wayland_executor, - Fd backing_store, + rust::Box client, + mir::Fd backing_store, int32_t claimed_size) : - wayland::ShmPool(resource, Version<1>{}), - wayland_executor{std::move(wayland_executor)}, + WlShmPoolImpl(std::move(client)), backing_store{shm::rw_pool_from_fd(std::move(backing_store), claimed_size)} { } @@ -244,12 +219,7 @@ auto wl_shm_format_to_drm_format(uint32_t format) -> mg::DRMFormat } } -void mf::ShmPool::create_buffer( - struct wl_resource* id, - int32_t offset, - int32_t width, int32_t height, - int32_t stride, - uint32_t format) +auto mf::ShmPool::create_buffer(int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) -> std::shared_ptr { auto const size = stride * height; std::unique_ptr backing_range; @@ -262,39 +232,38 @@ void mf::ShmPool::create_buffer( /* get_*_range throws a logic error when attempting to access outside the backing * store. This should be translated into a ProtocolError. */ - throw wayland::ProtocolError{ - resource, - wayland::Shm::Error::invalid_stride, + throw wayland_rs::ProtocolError{ + object_id(), + wayland_rs::WlShmImpl::Error::invalid_stride, "Attempt to create_buffer outside the range of the backing store"}; } // TODO: Extend DRMFormat to include bytes-per-pixel info and drop this hardcoded "4" if (stride < (width * 4)) { - throw wayland::ProtocolError{ - resource, - wayland::Shm::Error::invalid_stride, + throw wayland_rs::ProtocolError{ + object_id(), + wayland_rs::WlShmImpl::Error::invalid_stride, "Invalid stride %d (too small for width %d. Did you specify stride in pixels?)", stride, width}; } // TODO: Pull supported formats out of RenderingPlatform to support more than the required formats - if (format != wayland::Shm::Format::argb8888 && format != wayland::Shm::Format::xrgb8888) + if (format != wayland_rs::WlShmImpl::Format::argb8888 && format != wayland_rs::WlShmImpl::Format::xrgb8888) { - throw wayland::ProtocolError{ - resource, - wayland::Shm::Error::invalid_format, + throw wayland_rs::ProtocolError{ + object_id(), + wayland_rs::WlShmImpl::Error::invalid_format, "Invalid SHM format requested"}; } - new ShmBuffer{ - id, - wayland_executor, + return std::make_shared( + client->clone_box(), std::move(backing_range), geometry::Size{width, height}, geometry::Stride{stride}, wl_shm_format_to_drm_format(format) - }; + ); } void mf::ShmPool::resize(int32_t new_size) @@ -302,20 +271,8 @@ void mf::ShmPool::resize(int32_t new_size) backing_store->resize(new_size); } -mf::WlShm::WlShm(wl_display* display, std::shared_ptr wayland_executor) - : wayland::Shm::Global(display, Version<1>{}), - wayland_executor{std::move(wayland_executor)} -{ -} - -void mf::WlShm::bind(wl_resource* new_wl_shm) -{ - new Shm{new_wl_shm, wayland_executor}; -} - -mf::Shm::Shm(wl_resource* resource, std::shared_ptr wayland_executor) - : wayland::Shm(resource, Version<1>{}), - wayland_executor{std::move(wayland_executor)} +mf::Shm::Shm(rust::Box client) + : WlShmImpl(std::move(client)) { // TODO: send all the formats we support, beyond the mandatory ones. for (auto format : { Format::argb8888, Format::xrgb8888 }) @@ -324,15 +281,15 @@ mf::Shm::Shm(wl_resource* resource, std::shared_ptr wayland_executor) } } -void mf::Shm::create_pool(wl_resource* id, Fd fd, int32_t size) +auto mf::Shm::create_pool(int32_t fd, int32_t size) -> std::shared_ptr { if (size <= 0) { - throw wayland::ProtocolError{ - resource, - wayland::Shm::Error::invalid_stride, + throw wayland_rs::ProtocolError{ + object_id(), + Error::invalid_stride, "Invalid requested size"}; } - new ShmPool{id, wayland_executor, fd, size}; + return std::make_shared(client->clone_box(), Fd{fd}, size); } diff --git a/src/server/frontend_wayland/shm.h b/src/server/frontend_wayland/shm.h index a372af6628a..5e2c64b250c 100644 --- a/src/server/frontend_wayland/shm.h +++ b/src/server/frontend_wayland/shm.h @@ -15,20 +15,15 @@ */ #include -#include -#include "wayland_wrapper.h" +#include "wayland.h" #include +#include #include #include #include #include -namespace mir -{ -class Executor; -} - namespace mir::shm { class RWMappableRange; @@ -45,73 +40,48 @@ namespace mir::frontend class Shm; class ShmPool; -class ShmBuffer : public wayland::Buffer +class ShmBuffer : public wayland_rs::WlBufferImpl, public std::enable_shared_from_this { public: - auto data() -> std::shared_ptr; - - static auto from(wl_resource* resource) -> ShmBuffer*; -private: - friend class ShmPool; ShmBuffer( - struct wl_resource* resource, - std::shared_ptr wayland_executor, + rust::Box client, std::shared_ptr data, geometry::Size size, geometry::Stride stride, graphics::DRMFormat format); + auto data() -> std::shared_ptr; + +private: - wayland::Weak const weak_me; - std::shared_ptr const wayland_executor; std::shared_ptr const data_; geometry::Size const size_; geometry::Stride const stride_; graphics::DRMFormat const format_; }; -class ShmPool : public wayland::ShmPool +class ShmPool : public wayland_rs::WlShmPoolImpl { -private: - friend class Shm; +public: ShmPool( - struct wl_resource* resource, - std::shared_ptr wayland_executor, - Fd backing_store, + rust::Box client, + mir::Fd backing_store, int32_t claimed_size); - void create_buffer( - struct wl_resource* id, - int32_t offset, - int32_t width, int32_t height, - int32_t stride, - uint32_t format) override; +private: + + auto create_buffer(int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) -> std::shared_ptr override; void resize(int32_t new_size) override; - std::shared_ptr const wayland_executor; std::shared_ptr const backing_store; }; -class Shm : public wayland::Shm -{ -public: -private: - friend class WlShm; - Shm(struct wl_resource* resource, std::shared_ptr wayland_executor); - - void create_pool(struct wl_resource* id, Fd fd, int32_t size) override; - - std::shared_ptr const wayland_executor; -}; - -class WlShm : public wayland::Shm::Global +class Shm : public wayland_rs::WlShmImpl { public: - WlShm(wl_display* display, std::shared_ptr wayland_executor); + explicit Shm(rust::Box client); private: - void bind(wl_resource* new_wl_shm) override; - - std::shared_ptr const wayland_executor; + auto create_pool(int32_t fd, int32_t size) -> std::shared_ptr override; }; } diff --git a/src/server/frontend_wayland/wayland_connector.cpp b/src/server/frontend_wayland/wayland_connector.cpp index e725ab5db86..5c8077c80b2 100644 --- a/src/server/frontend_wayland/wayland_connector.cpp +++ b/src/server/frontend_wayland/wayland_connector.cpp @@ -15,9 +15,9 @@ */ #include "wayland_connector.h" -#ifdef MIR_ENABLE_RUST -#include "wayland_rs/src/ffi.rs.h" -#endif +#include "wayland_rs/wayland_rs_cpp/include/wayland.h" +#include "wayland_rs/wayland_rs_cpp/include/wayland_server_notification_handler.h" +#include "wl_client_registry.h" #include #include @@ -31,7 +31,6 @@ #include "shm.h" #include "frame_executor.h" #include "output_manager.h" -#include "wayland_executor.h" #include "desktop_file_manager.h" #include "foreign_toplevel_manager_v1.h" #include "wp_viewporter.h" @@ -72,88 +71,161 @@ namespace mir { namespace frontend { -class WlCompositor : public wayland::Compositor::Global +class WaylandConnector::WaylandCompositorGlobal { public: - WlCompositor( - struct wl_display* display, - std::shared_ptr const& wayland_executor, + WaylandCompositorGlobal( + std::shared_ptr const& client_registry, std::shared_ptr const& frame_callback_executor, std::shared_ptr const& allocator) - : Global(display, Version<6>()), + : allocator{allocator}, + frame_callback_executor{frame_callback_executor}, + client_registry{client_registry} + { + } + + void on_surface_created(rust::Box client_id, uint32_t id, std::function const& callback) + { + auto const wl_surface = resource ? WlSurface::from(resource) : nullptr; + if (wl_surface) + { + callback(wl_surface); + } + else + { + surface_callbacks[std::make_pair(std::move(client_id), id)].push_back(callback); + } + } + + std::map, uint32_t>, std::vector>> surface_callbacks; + std::shared_ptr const allocator; + std::shared_ptr const frame_callback_executor; +private: + std::shared_ptr client_registry; +}; + +class WaylandServerNotificationHandler : public wayland_rs::WaylandServerNotificationHandler +{ +public: + explicit WaylandServerNotificationHandler(std::shared_ptr const& client_registry) + : client_registry(client_registry) + {} + + auto client_added(rust::Box wayland_client) -> void override + { + client_registry->add_client(std::move(wayland_client)); + } + + auto client_removed(rust::Box id) -> void override + { + client_registry->delete_client(std::move(id)); + } + + std::shared_ptr client_registry; +}; + +class WlCompositor : public wayland_rs::WlCompositorImpl +{ +public: + explicit WlCompositor( + rust::Box client, + std::shared_ptr const& global, + std::shared_ptr const& client_registry, + std::shared_ptr const& frame_callback_executor, + std::shared_ptr const& allocator) + : WlCompositorImpl(std::move(client)), + global{global}, + client_registry{client_registry}, allocator{allocator}, - wayland_executor{wayland_executor}, frame_callback_executor{frame_callback_executor} { } - void on_surface_created(wl_client* client, uint32_t id, std::function const& callback); + auto create_surface() -> std::shared_ptr override + { + auto const surface = std::make_shared( + client->clone_box(), + client_registry, + frame_callback_executor, + allocator); + auto const key = std::make_pair(client->id(), wl_resource_get_id(new_surface)); + auto const callbacks = global->surface_callbacks.find(key); + if (callbacks != global->surface_callbacks.end()) + { + for (auto const& callback : callbacks->second) + { + callback(surface); + } + global->surface_callbacks.erase(callbacks); + } + } + + auto create_region() -> std::shared_ptr override + { + // TODO: Return a WlRegion here + return nullptr; + } private: + std::shared_ptr global; + std::shared_ptr client_registry; std::shared_ptr const allocator; - std::shared_ptr const wayland_executor; std::shared_ptr const frame_callback_executor; - std::map, std::vector>> surface_callbacks; - class Instance : wayland::Compositor +private: + +}; + +class GlobalFactory : public wayland_rs::GlobalFactory { +public: + GlobalFactory(std::shared_ptr const& client_registry, + std::shared_ptr const& compositor_global, + WlSeat* seat_global, + WaylandConnector::WaylandProtocolExtensionFilter const extension_filter) + : client_registry(client_registry), + compositor_global(compositor_global), + seat_global(seat_global), + extension_filter(std::move(extension_filter)) { - public: - Instance(wl_resource* new_resource, WlCompositor* compositor) - : mw::Compositor{new_resource, Version<6>()}, - compositor{compositor} - { - } + } - private: - void create_surface(wl_resource* new_surface) override; - void create_region(wl_resource* new_region) override; - WlCompositor* const compositor; - }; + auto can_view(rust::String interface_name, rust::Box client_id) -> bool override + { + auto const client = client_registry->from_id(std::move(client_id)); + return extension_filter(client->client_session(), interface_name.c_str()); + } - void bind(wl_resource* new_resource) + auto create_wl_compositor(rust::Box client) -> std::shared_ptr override { - new Instance{new_resource, this}; + return std::make_shared( + std::move(client), + compositor_global, + client_registry, + compositor_global->frame_callback_executor, + compositor_global->allocator + ); } -}; -void WlCompositor::on_surface_created(wl_client* client, uint32_t id, std::function const& callback) -{ - wl_resource* resource = wl_client_get_object(client, id); - auto const wl_surface = resource ? WlSurface::from(resource) : nullptr; - if (wl_surface) + auto create_wl_subcompositor(rust::Box client) -> std::shared_ptr override { - callback(wl_surface); + return std::make_shared(std::move(client)); } - else + + auto create_wl_seat(rust::Box client) -> std::shared_ptr override { - surface_callbacks[std::make_pair(client, id)].push_back(callback); + return seat_global->create(std::move(client)); } -} -void WlCompositor::Instance::create_surface(wl_resource* new_surface) -{ - auto const surface = new WlSurface{ - new_surface, - compositor->wayland_executor, - compositor->frame_callback_executor, - compositor->allocator}; - auto const key = std::make_pair(wl_resource_get_client(new_surface), wl_resource_get_id(new_surface)); - auto const callbacks = compositor->surface_callbacks.find(key); - if (callbacks != compositor->surface_callbacks.end()) + auto create_wl_shm(rust::Box client) -> std::shared_ptr override { - for (auto const& callback : callbacks->second) - { - callback(surface); - } - compositor->surface_callbacks.erase(callbacks); + return std::make_shared(std::move(client)); } - // Wayland ojects delete themselves -} -void WlCompositor::Instance::create_region(wl_resource* new_region) -{ - new WlRegion{new_region}; -} + std::shared_ptr client_registry; + std::shared_ptr compositor_global; + WlSeat* seat_global; + WaylandConnector::WaylandProtocolExtensionFilter const extension_filter; +}; } } @@ -224,17 +296,10 @@ auto mir::frontend::WaylandExtensions::get_extension(std::string const& name) co return {}; } -void mf::WaylandExtensions::run_builders(wl_display*, std::function&& work)> const&) +void mf::WaylandExtensions::run_builders(std::function&& work)> const&) { } -struct mf::WaylandConnector::ServerWrapper -{ - #ifdef MIR_ENABLE_RUST - rust::Box server; - #endif -}; - mf::WaylandConnector::WaylandConnector( std::shared_ptr const& shell, std::shared_ptr const& clock, @@ -266,39 +331,21 @@ mf::WaylandConnector::WaylandConnector( std::vector> const& render_platforms, std::shared_ptr const& cursor_observer_multiplexer) : extension_filter{extension_filter}, - display{wl_display_create(), &cleanup_display}, - // TODO(mattkae): Run the server and hook it up to the rest of the system - #ifdef MIR_ENABLE_RUST - server_wrapper{std::make_unique(wayland_rs::create_wayland_server())}, - #else - server_wrapper{std::make_unique()}, - #endif - pause_signal{eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE)}, - executor{std::make_shared(wl_display_get_event_loop(display.get()))}, - allocator{allocator_for_display(allocator, display.get(), executor)}, + server{wayland_rs::create_wayland_server()}, + client_registry{std::make_shared()}, + allocator{allocator_for_display(allocator)}, shell{shell}, extensions{std::move(extensions_)}, session_lock_{session_lock} { - if (pause_signal == mir::Fd::invalid) - { - BOOST_THROW_EXCEPTION((std::system_error{ - errno, - std::system_category(), - "Failed to create IPC pause notification eventfd"})); - } - - if (!display) + if (!server.into_raw()) { BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to create wl_display"}); } - wl_display_set_global_filter(display.get(), &wl_display_global_filter_func_thunk, this); - // Run the builders before creating the seat (because that's what GTK3 expects) - extensions->run_builders( - display.get(), - [executor=executor](std::function&& work) { executor->spawn(std::move(work)); }); + // TODO: Should this even take a function nowadays? + extensions->run_builders([](std::function&& work) { work(); }); /* * Here be Dragons! @@ -309,12 +356,10 @@ mf::WaylandConnector::WaylandConnector( * So far I've only found ones which expect wl_compositor before anything else, * so stick that first. */ - compositor_global = std::make_unique( - display.get(), - executor, + compositor_global = std::make_shared( + client_registry, std::make_shared(*main_loop), this->allocator); - subcompositor_global = std::make_unique(display.get()); auto const surface_registry = std::make_shared(); auto const action_group_manager = @@ -322,8 +367,6 @@ mf::WaylandConnector::WaylandConnector( auto const input_trigger_registry = std::make_shared(); auto const keyboard_state_tracker = std::make_shared(); seat_global = std::make_unique( - display.get(), - *executor, clock, input_hub, keyboard_observer_registrar, @@ -333,8 +376,6 @@ mf::WaylandConnector::WaylandConnector( input_trigger_registry, keyboard_state_tracker); output_manager = std::make_unique( - display.get(), - executor, display_config_registrar); desktop_file_manager = std::make_shared( @@ -348,8 +389,6 @@ mf::WaylandConnector::WaylandConnector( std::move(pointer_input_dispatcher)); extensions->init(WaylandExtensions::Context{ - display.get(), - executor, shell, session_authorizer, main_clipboard, @@ -377,8 +416,6 @@ mf::WaylandConnector::WaylandConnector( input_trigger_registry, keyboard_state_tracker}); - shm_global = std::make_unique(display.get(), executor); - viewporter = std::make_unique(display.get()); { @@ -429,23 +466,6 @@ mf::WaylandConnector::WaylandConnector( { fatal_error("Unable to bind Wayland socket"); } - - auto wayland_loop = wl_display_get_event_loop(display.get()); - - WlClient::setup_new_client_handler(display.get(), shell, session_authorizer, [this](WlClient& client) - { - int const fd = wl_client_get_fd(client.raw_client()); - auto const handler_iter = connect_handlers.find(fd); - - if (handler_iter != std::end(connect_handlers)) - { - auto const callback = handler_iter->second; - connect_handlers.erase(handler_iter); - callback(client.client_session()); - } - }); - - pause_source = wl_event_loop_add_fd(wayland_loop, pause_signal, WL_EVENT_READABLE, &halt_eventloop, display.get()); } namespace @@ -493,20 +513,25 @@ mf::WaylandConnector::~WaylandConnector() void mf::WaylandConnector::start() { dispatch_thread = std::thread{ - [](wl_display* d) + [ + wayland_display = wayland_display, + client_registry = client_registry, + compositor_global = compositor_global, + extension_filter = extension_filter, + seat_global = seat_global.get() + ](wayland_rs::WaylandServer* server) { mir::set_thread_name("Mir/Wayland"); - wl_display_run(d); + server->run(wayland_display, + std::make_unique(client_registry, compositor_global, seat_global, extension_filter), + std::make_unique(client_registry)); }, - display.get()}; + server.into_raw()}; } void mf::WaylandConnector::stop() { - if (eventfd_write(pause_signal, 1) < 0) - { - log_error("WaylandConnector::stop() failed to send IPC eventloop pause signal: %s (%i)", mir::errno_to_cstr(errno), errno); - } + server->stop(); if (dispatch_thread.joinable()) { dispatch_thread.join(); @@ -620,18 +645,6 @@ void mf::WaylandConnector::for_each_output_binding( } } -bool mf::WaylandConnector::wl_display_global_filter_func_thunk(wl_client const* client, wl_global const* global, void *data) -{ - return static_cast(data)->wl_display_global_filter_func(client, global); -} - -bool mf::WaylandConnector::wl_display_global_filter_func(wl_client const* client, wl_global const* global) const -{ - auto const* const interface = wl_global_get_interface(global); - auto const session = get_session(client); - return extension_filter(session, interface->name); -} - auto mir::frontend::get_session(wl_client const* wl_client) -> std::shared_ptr { return WlClient::from(wl_client).client_session(); diff --git a/src/server/frontend_wayland/wayland_connector.h b/src/server/frontend_wayland/wayland_connector.h index 83ec47a5c98..84b29343c03 100644 --- a/src/server/frontend_wayland/wayland_connector.h +++ b/src/server/frontend_wayland/wayland_connector.h @@ -20,6 +20,7 @@ #include #include "wayland_wrapper.h" #include "input_trigger_registry.h" +#include "wayland_rs/src/ffi.rs.h" #include #include @@ -33,6 +34,8 @@ #include #include +#include "wl_client_registry.h" + namespace mir { class Executor; @@ -105,7 +108,6 @@ class WaylandExtensions /// The resources needed to init Wayland extensions struct Context { - wl_display* display; std::shared_ptr wayland_executor; std::shared_ptr shell; std::shared_ptr session_authorizer; @@ -140,7 +142,7 @@ class WaylandExtensions WaylandExtensions(WaylandExtensions const&) = delete; WaylandExtensions& operator=(WaylandExtensions const&) = delete; - virtual void run_builders(wl_display* display, std::function&& work)> const& run_on_wayland_mainloop); + virtual void run_builders(std::function&& work)> const& run_on_wayland_mainloop); void init(Context const& context); @@ -159,6 +161,7 @@ class WaylandConnector : public Connector, public WaylandTools { public: using WaylandProtocolExtensionFilter = std::function const&, char const*)>; + class WaylandCompositorGlobal; WaylandConnector( std::shared_ptr const& shell, @@ -212,8 +215,6 @@ class WaylandConnector : public Connector, public WaylandTools auto get_extension(std::string const& name) const -> std::shared_ptr; private: - struct ServerWrapper; - void for_each_output_binding( wayland::Client* client, graphics::DisplayConfigurationOutputId output, @@ -233,25 +234,20 @@ class WaylandConnector : public Connector, public WaylandTools */ WaylandProtocolExtensionFilter const extension_filter; - std::unique_ptr const display; - std::unique_ptr server_wrapper; - mir::Fd const pause_signal; - std::unique_ptr compositor_global; - std::unique_ptr subcompositor_global; + rust::Box server; + std::shared_ptr client_registry; + std::shared_ptr compositor_global; std::unique_ptr seat_global; std::unique_ptr output_manager; std::shared_ptr desktop_file_manager; std::unique_ptr data_device_manager_global; - std::unique_ptr shm_global; std::unique_ptr viewporter; std::unique_ptr drm_syncobj; - std::shared_ptr const executor; std::shared_ptr const allocator; std::shared_ptr const shell; std::unique_ptr const extensions; std::shared_ptr session_lock_; std::thread dispatch_thread; - wl_event_source* pause_source; std::string wayland_display; // Only accessed on event loop diff --git a/src/server/frontend_wayland/wayland_executor.cpp b/src/server/frontend_wayland/wayland_executor.cpp deleted file mode 100644 index dd17567029a..00000000000 --- a/src/server/frontend_wayland/wayland_executor.cpp +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "wayland_executor.h" - -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace mf = mir::frontend; - -/* - * Theory of execution: - * - * Like many interactions with Wayland API we have the problem that we can only - * call Wayland functions on the mainloop thread *and* that the Wayland objects - * can be destroyed from underneath the wrappers. - * - * The solution we use here is to share ownership of the workqueue between the - * wl_event_source and the WaylandExecutor. WaylandExecutor can then always - * enqueue new work, even if no more work is going to be processed, and the work - * processing function always has a reference to the workqueue state. - */ - -class mf::WaylandExecutor::State -{ -private: - enum class ExecutionState - { - Running, - TerminationRequested, - Stopped - }; -public: - explicit State(wl_event_loop* loop) - : loop{loop} - { - enqueue( - []() - { - on_wayland_thread = true; - }); - } - - void enqueue(std::function&& work) - { - if (on_wayland_thread) - { - work(); - return; - } - - if (state == ExecutionState::Running) - { - std::lock_guard lock{mutex}; - if (state == ExecutionState::Running) - { - workqueue.emplace_back(std::move(work)); - } - } - // If we've been terminated then drop the work on the floor, letting the - // std::function destructor clean up any necessary state. - } - - void enqueue_termination(std::function&& terminator) - { - std::lock_guard lock{mutex}; - if (state == ExecutionState::Running) - { - workqueue.emplace_front(std::move(terminator)); - on_wayland_thread = false; - state = ExecutionState::TerminationRequested; - } - } - - std::function get_work() - { - std::lock_guard lock{mutex}; - if (!workqueue.empty()) - { - auto const work = std::move(workqueue.front()); - workqueue.pop_front(); - return work; - } - return {}; - } - - auto drain() - { - std::unique_lock lock{mutex}; - - if (state == ExecutionState::TerminationRequested) - { - // If we've been asked to terminate then the front of the workqueue - // will contain the termination request. - { - std::function const work = std::move(workqueue.front()); - lock.unlock(); - - work(); - } - lock.lock(); - } - - on_wayland_thread = false; - state = ExecutionState::Stopped; - workqueue.clear(); - - return lock; - } - - static int on_notify(int fd, uint32_t, void* data); -private: - static thread_local bool on_wayland_thread; - std::mutex mutex; - /* - * `state` is atomic because it is used in a double-checked locking pattern in `enqueue()`. - * The first check of `state` (outside the mutex) allows fast-path rejection of work when - * the executor is not running, avoiding unnecessary locking. The second check (inside the mutex) - * ensures correctness in the presence of concurrent state changes. This pattern requires `state` - * to be atomic to prevent data races and ensure thread safety. - */ - std::atomic state{ExecutionState::Running}; - wl_event_loop* const loop; - std::deque> workqueue; -}; - -thread_local bool mf::WaylandExecutor::State::on_wayland_thread{false}; - -namespace -{ -class EventLoopDestroyedHandler -{ -public: - static void setup_destruction_handler_for_loop( - wl_event_loop* loop, - wl_event_source* source, - std::shared_ptr state) - { - new EventLoopDestroyedHandler(loop, source, std::move(state)); - } - - static void remove_destruction_handler_for_loop( - wl_event_loop* loop) - { - auto listener = - wl_event_loop_get_destroy_listener(loop, &EventLoopDestroyedHandler::on_destroyed); - - EventLoopDestroyedHandler* me; - me = wl_container_of(listener, me, destruction_listener); - delete me; - - wl_list_remove(&listener->link); - } -private: - EventLoopDestroyedHandler( - wl_event_loop* loop, - wl_event_source* source, - std::shared_ptr state) - : source{source}, - work_queue{std::move(state)} - { - destruction_listener.notify = &EventLoopDestroyedHandler::on_destroyed; - wl_event_loop_add_destroy_listener(loop, &destruction_listener); - } - - static void on_destroyed(wl_listener* listener, void*) - { - EventLoopDestroyedHandler* me; - - me = wl_container_of(listener, me, destruction_listener); - - { - /* - * We drain the work queue to ensure that any shutdown work has a chance - * to be processed. - */ - auto queue_lock = me->work_queue->drain(); - - /* - * We take no weak pointers to the work_queue, so if it's unique now it's - * guaranteed to remain unique. We've got a lock on the queue, so - * ~WaylandExecutor can't sneakily add a cleanup work item we would never - * process. - * - * If work_queue *is* unique that means that ~WaylandExecutor has already - * unregistered the event source, so we should not try to do so again. - */ - if (me->work_queue.use_count() != 1) - { - wl_event_source_remove(me->source); - } - } - - delete me; - } - - wl_event_source* const source; - std::shared_ptr const work_queue; - - wl_listener destruction_listener; -}; - -static_assert( - std::is_standard_layout::value, - "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour"); -} - -int mf::WaylandExecutor::State::on_notify(int fd, uint32_t, void* data) -{ - auto state = static_cast(data); - - eventfd_t unused; - if (auto err = eventfd_read(fd, &unused)) - { - mir::log_error( - "eventfd_read failed to consume wakeup notification: %s (%i)", - mir::errno_to_cstr(err), - err); - } - - while (auto work = state->get_work()) - { - try - { - work(); - } - catch (...) - { - mir::log( - mir::logging::Severity::critical, - MIR_LOG_COMPONENT, - std::current_exception(), - "Exception processing Wayland event loop work item"); - } - } - if (state->state != ExecutionState::Running) - { - EventLoopDestroyedHandler::remove_destruction_handler_for_loop(state->loop); - } - - return 0; -} - - - -mf::WaylandExecutor::WaylandExecutor(wl_event_loop* loop) - : state{std::make_shared(loop)}, - notify_fd{eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE | EFD_NONBLOCK)}, - source{wl_event_loop_add_fd( - loop, - notify_fd, - WL_EVENT_READABLE, - &State::on_notify, - state.get())} -{ - if (notify_fd == mir::Fd::invalid) - { - BOOST_THROW_EXCEPTION((std::system_error{ - errno, - std::system_category(), - "Failed to create IPC pause notification eventfd"})); - } - if (!source) - { - BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to create Wayland notify source"})); - } - EventLoopDestroyedHandler::setup_destruction_handler_for_loop(loop, source, state); - - // Messy, but although the State ctor queues work it can't "notify" the event loop work is pending - if (auto err = eventfd_write(notify_fd, 1)) - { - BOOST_THROW_EXCEPTION( - (std::system_error{err, std::system_category(), "eventfd_write failed to notify event loop"})); - } -} - -mf::WaylandExecutor::~WaylandExecutor() -{ - /* - * We need to move state into the functor; the destruction machinery relies - * on WaylandExecutor *not* having a ref on state to determine whether - * to unregister the source itself. - * - * If we enqueue the work before dropping WaylandExecutors' ref there's a potential - * race in destruction: - * T1: enqueue(cleanup_functor) adds the functor to the queue. - * T2: The wl_event_loop is destroyed, calling EventLoopDestroyedHandler::on_destroyed() - * T2: on_destroyed() drains the workqueue, calling cleanup_functor() and so unregistering - * the source. - * T2: on_destroyed() checks the refcount of work_queue, finding that it's not unique. - * T2: on_destroyed() unregisters the source, causing a double-free - * T1: ~WaylandExecutor completes, dropping the ref on the work queue. - */ - auto const raw_state = state.get(); - auto cleanup_functor = - [state_holder = std::move(state), source = this->source]() - { - wl_event_source_remove(source); - }; - - raw_state->enqueue_termination(std::move(cleanup_functor)); - - if (auto err = eventfd_write(notify_fd, 1)) - { - mir::log_critical( - "Failed to create event notification for ~WaylandExecutor: %s (%i)", - mir::errno_to_cstr(err), - err); - } -} - -void mf::WaylandExecutor::spawn (std::function&& work) -{ - state->enqueue(std::move(work)); - - if (auto err = eventfd_write(notify_fd, 1)) - { - BOOST_THROW_EXCEPTION( - (std::system_error{err, std::system_category(), "eventfd_write failed to notify event loop"})); - } -} diff --git a/src/server/frontend_wayland/wayland_executor.h b/src/server/frontend_wayland/wayland_executor.h deleted file mode 100644 index 1782dd0ca5f..00000000000 --- a/src/server/frontend_wayland/wayland_executor.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_FRONTEND_EXECUTOR_H -#define MIR_FRONTEND_EXECUTOR_H - -#include -#include - -#include - -#include -#include -#include - -namespace mir -{ -namespace frontend -{ -class WaylandExecutor : public Executor -{ -public: - explicit WaylandExecutor(wl_event_loop* loop); - ~WaylandExecutor(); - - void spawn(std::function&& work) override; - - class State; -private: - std::shared_ptr state; - mir::Fd const notify_fd; - wl_event_source* const source; -}; -} -} - -#endif //MIR_FRONTEND_EXECUTOR_H diff --git a/src/server/frontend_wayland/wayland_rs/.gitignore b/src/server/frontend_wayland/wayland_rs/.gitignore index c49fe20c815..e9c4068cc9b 100644 --- a/src/server/frontend_wayland/wayland_rs/.gitignore +++ b/src/server/frontend_wayland/wayland_rs/.gitignore @@ -6,6 +6,8 @@ src/wayland_server_generated.rs wayland_rs_cpp/include/* wayland_rs_cpp/src/* +!wayland_rs_cpp/include/lifetime_tracker.h !wayland_rs_cpp/include/protocol_error.h !wayland_rs_cpp/include/weak.h +!wayland_rs_cpp/src/lifetime_tracker.cpp !wayland_rs_cpp/src/protocol_error.cpp diff --git a/src/server/frontend_wayland/wayland_rs/CMakeLists.txt b/src/server/frontend_wayland/wayland_rs/CMakeLists.txt index 41067a8eae1..342be784da1 100644 --- a/src/server/frontend_wayland/wayland_rs/CMakeLists.txt +++ b/src/server/frontend_wayland/wayland_rs/CMakeLists.txt @@ -49,6 +49,7 @@ set_source_files_properties(${wayland_rs_generated_sources} PROPERTIES GENERATED target_sources(mirwayland_rs-cxxbridge PRIVATE ${wayland_rs_generated_sources} + ${CMAKE_CURRENT_SOURCE_DIR}/wayland_rs_cpp/src/lifetime_tracker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/wayland_rs_cpp/src/protocol_error.cpp ) diff --git a/src/server/frontend_wayland/wayland_rs/build_script/cpp_builder.rs b/src/server/frontend_wayland/wayland_rs/build_script/cpp_builder.rs index 9de2da938d3..2f7dd2529d3 100644 --- a/src/server/frontend_wayland/wayland_rs/build_script/cpp_builder.rs +++ b/src/server/frontend_wayland/wayland_rs/build_script/cpp_builder.rs @@ -100,7 +100,11 @@ impl CppBuilder { // Generate classes for class in &namespace.classes { - result.push_str(&format!("class {}\n", class.name)); + if let Some(superclass) = &class.superclass { + result.push_str(&format!("class {} : public {}\n", class.name, superclass)); + } else { + result.push_str(&format!("class {}\n", class.name)); + } result.push_str("{\n"); result.push_str("public:\n"); @@ -149,6 +153,16 @@ impl CppBuilder { } } + for member in &class.public_members { + let const_str = if member.is_const { " const" } else { "" }; + result.push_str(&format!( + " {}{} {};\n", + cpp_arg_type_to_cpp_source(&member.cpp_type, true), + const_str, + member.name + )); + } + if !class.protected_constructor_args.is_empty() || !class.protected_members.is_empty() { @@ -181,9 +195,11 @@ impl CppBuilder { } for member in &class.protected_members { + let const_str = if member.is_const { " const" } else { "" }; result.push_str(&format!( - " {} {};\n", + " {}{} {};\n", cpp_arg_type_to_cpp_source(&member.cpp_type, true), + const_str, member.name )); } @@ -193,16 +209,19 @@ impl CppBuilder { result.push_str("private:\n"); for member in &class.private_members { + let const_str = if member.is_const { " const" } else { "" }; if member.optional { result.push_str(&format!( - " std::optional<{}> {};\n", + " std::optional<{}>{} {};\n", cpp_arg_type_to_cpp_source(&member.cpp_type, true), + const_str, member.name )); } else { result.push_str(&format!( - " {} {};\n", + " {}{} {};\n", cpp_arg_type_to_cpp_source(&member.cpp_type, true), + const_str, member.name )); } @@ -378,8 +397,10 @@ impl CppNamespace { pub struct CppClass { pub name: String, + pub superclass: Option, pub methods: Vec, pub enums: Vec, + pub public_members: Vec, pub protected_constructor_args: Vec, pub protected_members: Vec, pub private_members: Vec, @@ -389,14 +410,20 @@ impl CppClass { pub fn new(name: impl Into) -> CppClass { CppClass { name: sanitize_identifier(&name.into()), + superclass: None, methods: vec![], enums: vec![], + public_members: vec![], protected_constructor_args: vec![], protected_members: vec![], private_members: vec![], } } + pub fn set_superclass(&mut self, name: impl Into) { + self.superclass = Some(name.into()); + } + pub fn add_method(&mut self, method: CppMethod) -> &mut CppMethod { self.methods.push(method); self.methods @@ -411,6 +438,13 @@ impl CppClass { .expect("enums cannot be empty after push") } + pub fn add_public_member(&mut self, member: CppArg) -> &mut CppArg { + self.public_members.push(member); + self.public_members + .last_mut() + .expect("public_members cannot be empty after push") + } + pub fn add_protected_constructor_arg(&mut self, arg: CppArg) -> &mut CppArg { self.protected_constructor_args.push(arg); self.protected_constructor_args @@ -418,13 +452,6 @@ impl CppClass { .expect("protected_constructor_args cannot be empty after push") } - pub fn add_protected_member(&mut self, member: CppArg) -> &mut CppArg { - self.protected_members.push(member); - self.protected_members - .last_mut() - .expect("members cannot be empty after push") - } - pub fn add_private_member(&mut self, member: CppArg) -> &mut CppArg { self.private_members.push(member); self.private_members @@ -521,7 +548,6 @@ pub enum CppType { CppF64, String, Object(String), - Weak(String), Array, Fd, Box(String), @@ -539,9 +565,6 @@ fn cpp_return_type_to_cpp_source(cpp_type: &CppType) -> String { CppType::Object(name) => { format!("std::shared_ptr<{}>", name) } - CppType::Weak(name) => { - format!("wayland_rs::Weak<{}>", name) - } CppType::Array => "std::vector".to_string(), CppType::Fd => "int32_t".to_string(), CppType::Box(name) => { @@ -563,7 +586,6 @@ fn cpp_arg_type_to_cpp_source(cpp_type: &CppType, originates_from_rust: bool) -> (CppType::CppF64, _) => "double".into(), (CppType::Fd, _) => "int32_t".into(), (CppType::Object(name), _) => format!("std::shared_ptr<{}> const&", name), - (CppType::Weak(name), _) => format!("wayland_rs::Weak<{}> const&", name), (CppType::Box(name), _) => { if originates_from_rust { format!("rust::Box<{}>", name) @@ -593,7 +615,6 @@ fn cpp_return_type_to_rust_source(cpp_type: &CppType) -> TokenStream { } CppType::Array => quote! { &CxxVector }, CppType::Fd => quote! { i32 }, - CppType::Weak(_) => unreachable!("Weak type should not generate Rust code"), CppType::Box(name) => { let type_name = format_ident!("{}", name); quote! { &Box<#type_name> } @@ -631,7 +652,6 @@ fn cpp_arg_type_to_rust_source(cpp_type: &CppType, originates_from_rust: bool) - } } CppType::Fd => quote! { i32 }, - CppType::Weak(_) => unreachable!("Weak type should not generate Rust code"), CppType::Box(name) => { let type_name = format_ident!("{}", name); if originates_from_rust { @@ -760,6 +780,7 @@ pub struct CppArg { name: String, has_name: Option, optional: bool, + is_const: bool, } impl CppArg { @@ -774,9 +795,15 @@ impl CppArg { None }, optional, + is_const: false, } } + pub fn set_const(&mut self) -> &mut Self { + self.is_const = true; + self + } + pub fn name(&self) -> &str { &self.name } diff --git a/src/server/frontend_wayland/wayland_rs/build_script/ffi_generation.rs b/src/server/frontend_wayland/wayland_rs/build_script/ffi_generation.rs index 06433e67719..11bfac65e88 100644 --- a/src/server/frontend_wayland/wayland_rs/build_script/ffi_generation.rs +++ b/src/server/frontend_wayland/wayland_rs/build_script/ffi_generation.rs @@ -92,6 +92,11 @@ fn generate_ffi_for_protocol(protocol: &WaylandProtocol) -> TokenStream { } fn generate_ffi_for_interface(interface: &WaylandInterface) -> TokenStream { + let interface_name_ext = format_ident!( + "{}", + format_wayland_interface_to_rust_extension_struct(&interface.name) + ); + let events: Vec = interface .items .iter() @@ -102,6 +107,7 @@ fn generate_ffi_for_interface(interface: &WaylandInterface) -> TokenStream { .collect(); quote! { + fn post_error(self: &mut #interface_name_ext, code: u32, message: &CxxString); #(#events)* } } diff --git a/src/server/frontend_wayland/wayland_rs/build_script/main.rs b/src/server/frontend_wayland/wayland_rs/build_script/main.rs index 5414403520e..aac5cb6871c 100644 --- a/src/server/frontend_wayland/wayland_rs/build_script/main.rs +++ b/src/server/frontend_wayland/wayland_rs/build_script/main.rs @@ -817,8 +817,8 @@ fn create_cpp_builder(protocol: &WaylandProtocol) -> CppBuilder { // Use ffi_fwd.h (generated alongside the protocol headers) instead of the // CXX-generated ffi.rs.h to avoid a circular include dependency: // ffi.rs.h → include/*.h → ffi.rs.h + builder.add_header_include("\"lifetime_tracker.h\""); builder.add_header_include("\"ffi_fwd.h\""); - builder.add_header_include("\"weak.h\""); builder.add_header_include(""); builder.add_header_include(""); builder.add_header_include(""); @@ -852,6 +852,7 @@ fn write_cpp_source(builder: &CppBuilder) { fn wayland_interface_to_cpp_class(interface: &WaylandInterface) -> CppClass { let class_name = format_wayland_interface_to_cpp_class(&interface.name); let mut class = CppClass::new(class_name); + class.set_superclass("LifetimeTracker"); let methods = interface .items .iter() @@ -923,6 +924,17 @@ fn wayland_interface_to_cpp_class(interface: &WaylandInterface) -> CppClass { ); class.add_method(get_box_method); + // Add a post_error method that posts a protocol error to the client for this resource. + // This follows the same pattern as event-sending methods, routing through the Rust + // middleware Ext type to call wayland-server's DisplayHandle::post_error(). + let mut post_error_method = CppMethod::new("post_error", None, false, false, false, true); + post_error_method.add_arg(CppArg::new(CppType::CppU32, "code", false)); + post_error_method.add_arg(CppArg::new(CppType::String, "message", false)); + post_error_method.set_body( + "if (!instance_.has_value()) {\n throw \"post_error() used before associate()\";\n}\ninstance_.value()->post_error(code, message);", + ); + class.add_method(post_error_method); + // Add a protected constructor and member so that subclasses know which client // they are serving and can interact with it as they please. class.add_protected_constructor_arg(CppArg::new( @@ -930,12 +942,13 @@ fn wayland_interface_to_cpp_class(interface: &WaylandInterface) -> CppClass { "client", false, )); - class.add_protected_member(CppArg::new( - CppType::Box("WaylandClient".to_string()), - "client", - false, - )); - + class + .add_public_member(CppArg::new( + CppType::Box("WaylandClient".to_string()), + "client", + false, + )) + .set_const(); for method in methods { class.add_method(method); } @@ -1011,124 +1024,18 @@ fn wayland_request_to_cpp_method(method: &WaylandRequest) -> Vec { .filter(|arg| arg.type_ != WaylandArgType::NewId) .map(wayland_arg_to_cpp_arg); - // If a C++ argument is being sent from Rust to C++ as a shared_ptr, we do NOT want - // to encourage the protocol implementer to hold a shared reference to the object, as - // that muddies up the lifetimes significantly. Only the Rust Wayland frontend should - // have access to the lifetime. However, it is important for the protocol business logic - // to be able to interact with other protocol implementations. Hence, we wrap the shared_ptr - // in our own "Weak" construct. - // - // If this is the case, we need to do the following: - // 1. Generate a different virtual method that is NOT called from Rust which will handle - // the logic using the weak value. - // 2. Make the original handler NOT be virtual, as the overridable logic will be delegated - // to the new method from #1. - let wayland_weak_transformers: Vec = args - .clone() - .flat_map(|arg| match arg.cpp_type() { - CppType::Object(type_name) => Some(format!( - "auto const wrapped_{name} = wayland_rs::Weak<{type_name}>({name});", - name = arg.name(), - type_name = type_name - )), - _ => None, - }) - .collect(); - - let delegation_args: Vec = args - .clone() - .flat_map(|arg| { - let call_arg = match arg.cpp_type() { - CppType::Object(_) => format!("wrapped_{}", arg.name()), - _ => arg.name().to_string(), - }; - if let Some(has_name) = arg.has_name() { - vec![call_arg, has_name] - } else { - vec![call_arg] - } - }) - .collect(); - - let has_retval = retval.is_some(); - let mut cpp_method = CppMethod::new( - method.name.as_str(), - retval, - wayland_weak_transformers.is_empty(), - true, - true, - true, - ); + let mut cpp_method = CppMethod::new(method.name.as_str(), retval, true, true, true, true); for arg in args { cpp_method.add_arg(arg); } if let Some(type_) = &method.type_ { if type_ == "destructor" { - assert!(wayland_weak_transformers.is_empty()); cpp_method.set_body(""); } } - if !wayland_weak_transformers.is_empty() { - // Build the body: wrap shared_ptrs in Weak, then delegate to the virtual overload - let return_prefix = if has_retval { "return " } else { "" }; - let delegation_call = format!( - "{}{}({});", - return_prefix, - sanitize_identifier(&method.name), - delegation_args.join(", ") - ); - let mut body_lines = wayland_weak_transformers; - body_lines.push(delegation_call); - cpp_method.set_body(body_lines.join("\n")); - - // Generate the virtual method that protocol implementers override. - // This method uses Weak args instead of shared_ptr args. - let virtual_retval = method - .args - .iter() - .find(|arg| arg.type_ == WaylandArgType::NewId) - .map(|new_id_arg| { - CppType::Object(format_wayland_interface_to_cpp_class( - new_id_arg - .interface - .as_ref() - .expect("NewId is missing interface"), - )) - }); - let mut virtual_method = CppMethod::new( - method.name.as_str(), - virtual_retval, - true, - true, - true, - false, - ); - for wayland_arg in method - .args - .iter() - .filter(|arg| arg.type_ != WaylandArgType::NewId) - { - let cpp_arg = wayland_arg_to_cpp_arg(wayland_arg); - match cpp_arg.cpp_type() { - CppType::Object(type_name) => { - virtual_method.add_arg(CppArg::new( - CppType::Weak(type_name.clone()), - wayland_arg.name.as_str(), - wayland_arg.allow_null.unwrap_or(false), - )); - } - _ => { - virtual_method.add_arg(cpp_arg); - } - } - } - - vec![cpp_method, virtual_method] - } else { - vec![cpp_method] - } + vec![cpp_method] } fn wayland_event_to_cpp_method(event: &WaylandEvent) -> CppMethod { diff --git a/src/server/frontend_wayland/wayland_rs/build_script/protocol_middleware_generation.rs b/src/server/frontend_wayland/wayland_rs/build_script/protocol_middleware_generation.rs index 9c355a4656a..4ca2fe8e5b9 100644 --- a/src/server/frontend_wayland/wayland_rs/build_script/protocol_middleware_generation.rs +++ b/src/server/frontend_wayland/wayland_rs/build_script/protocol_middleware_generation.rs @@ -127,6 +127,18 @@ fn generate_extension_for_interface(interface: &WaylandInterface) -> Option Box { Box::new(self.clone()) } + + /// Clone the client to a new box. + pub fn clone_box(&self) -> Box { + Box::new(*self.clone()) + } } /// An opaque ID for the WaylandClient. diff --git a/include/wayland/mir/wayland/lifetime_tracker.h b/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/include/lifetime_tracker.h similarity index 68% rename from include/wayland/mir/wayland/lifetime_tracker.h rename to src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/include/lifetime_tracker.h index d16a8453358..6b1a1072823 100644 --- a/include/wayland/mir/wayland/lifetime_tracker.h +++ b/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/include/lifetime_tracker.h @@ -2,7 +2,7 @@ * Copyright © Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, + * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, @@ -14,28 +14,22 @@ * along with this program. If not, see . */ -#ifndef MIR_WAYLAND_LIFETIME_TRACKER_H_ -#define MIR_WAYLAND_LIFETIME_TRACKER_H_ - -#include +#ifndef MIR_WAYLANDRS_LIFETIME_TRACKER +#define MIR_WAYLANDRS_LIFETIME_TRACKER +#include #include +#include #include namespace mir { -namespace wayland -{ -namespace detail +namespace wayland_rs { -struct DestroyListenerIdTag; -} -typedef IntWrapper DestroyListenerId; - -/// The base class of any object that wants to provide a destroyed flag -/// The destroyed flag is only created when needed and automatically set to true on destruction -/// This pattern is only safe in a single-threaded context +/// The base class of any object that wants to provide a destroyed flag. +/// The destroyed flag is only created when needed and automatically set to true on destruction. +/// All public methods are thread-safe. class LifetimeTracker { public: @@ -44,15 +38,18 @@ class LifetimeTracker LifetimeTracker& operator=(LifetimeTracker const&) = delete; virtual ~LifetimeTracker(); + /// The pointed-at bool contains false if this object is still alive and true if it has been destroyed. auto destroyed_flag() const -> std::shared_ptr; + /// The given function will be called just before the object is marked as destroyed. The returned ID can be used - /// to remove the listener in which case it is never called. DestroyListenerId{} (value 0) is never returned, and so - /// it can be used as a null ID. Destroy listener call order is undefined. - auto add_destroy_listener(std::function listener) const -> DestroyListenerId; + /// to remove the listener in which case it is never called. 0 is never returned and can be used as a null ID. + /// Destroy listener call order is undefined. + auto add_destroy_listener(std::function listener) const -> uint64_t; + /// If the given ID maps to a destroy listener, that listener is dropped without being called. If the listener has /// already been dropped or never existed, this call is ignored. - void remove_destroy_listener(DestroyListenerId id) const; + void remove_destroy_listener(uint64_t id) const; protected: /// Subclasses are not required to call this, but may do so during the destruction process if the object needs to @@ -61,12 +58,10 @@ class LifetimeTracker private: struct Impl; - - /// Since many Wayland objects are created and the features of this class are used for only a few, impl is created - /// lazily to conserve memory. - std::unique_ptr mutable impl; + std::unique_ptr const impl; }; + } } -#endif // MIR_WAYLAND_LIFETIME_TRACKER_H_ +#endif // MIR_WAYLANDRS_LIFETIME_TRACKER diff --git a/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/include/weak.h b/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/include/weak.h deleted file mode 100644 index bcc39b12089..00000000000 --- a/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/include/weak.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLANDRS_WEAK -#define MIR_WAYLANDRS_WEAK - -#include -#include -#include -#include - -namespace mir -{ -namespace wayland_rs -{ -template -class Weak -{ -public: - explicit Weak(std::shared_ptr const& ptr) - : ptr_{ptr} - { - } - - Weak(Weak const& weak) = default; - - template - decltype(auto) with_value(F&& f) const - { - if (auto locked = ptr_.lock()) - return std::forward(f)(*locked); - BOOST_THROW_EXCEPTION(std::logic_error{"Accessing expired wayland_rs::Weak"}); - } - - operator bool() const - { - return !ptr_.expired(); - } - - auto is(T const& other) const -> bool - { - auto locked = ptr_.lock(); - return locked && locked.get() == &other; - } - - auto operator==(Weak const& other) const -> bool - { - return !ptr_.owner_before(other.ptr_) && !other.ptr_.owner_before(ptr_); - } - - auto operator!=(Weak const& other) const -> bool - { - return !(*this == other); - } - - auto operator=(Weak const&) -> Weak& = default; - -private: - std::weak_ptr ptr_; -}; -} -} - -#endif // MIR_WAYLANDRS_WEAK diff --git a/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/src/lifetime_tracker.cpp b/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/src/lifetime_tracker.cpp new file mode 100644 index 00000000000..ab7acfb51af --- /dev/null +++ b/src/server/frontend_wayland/wayland_rs/wayland_rs_cpp/src/lifetime_tracker.cpp @@ -0,0 +1,91 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "lifetime_tracker.h" + +#include +#include + +namespace mrs = mir::wayland_rs; + +struct mrs::LifetimeTracker::Impl +{ + std::mutex mutable mutex; + std::shared_ptr destroyed{nullptr}; + std::map> destroy_listeners; + uint64_t last_id{0}; + bool already_destroyed{false}; +}; + +mrs::LifetimeTracker::LifetimeTracker() + : impl{std::make_unique()} +{ +} + +mrs::LifetimeTracker::~LifetimeTracker() +{ + mark_destroyed(); +} + +auto mrs::LifetimeTracker::destroyed_flag() const -> std::shared_ptr +{ + std::lock_guard lock{impl->mutex}; + if (!impl->destroyed) + { + impl->destroyed = std::make_shared(false); + } + return impl->destroyed; +} + +auto mrs::LifetimeTracker::add_destroy_listener(std::function listener) const -> uint64_t +{ + std::lock_guard lock{impl->mutex}; + auto const id = impl->last_id + 1; + impl->last_id = id; + impl->destroy_listeners[id] = std::move(listener); + return id; +} + +void mrs::LifetimeTracker::remove_destroy_listener(uint64_t id) const +{ + std::lock_guard lock{impl->mutex}; + impl->destroy_listeners.erase(id); +} + +void mrs::LifetimeTracker::mark_destroyed() const +{ + decltype(impl->destroy_listeners) local_listeners; + { + std::lock_guard lock{impl->mutex}; + if (impl->already_destroyed) + return; + impl->already_destroyed = true; + local_listeners = std::move(impl->destroy_listeners); + impl->destroy_listeners.clear(); + } + // Call listeners outside the lock to avoid deadlocks + for (auto const& listener : local_listeners) + { + listener.second(); + } + { + std::lock_guard lock{impl->mutex}; + if (impl->destroyed) + { + *impl->destroyed = true; + } + } +} diff --git a/src/server/frontend_wayland/wl_client.cpp b/src/server/frontend_wayland/wl_client.cpp index 4728f27bf3e..5bae7010eaa 100644 --- a/src/server/frontend_wayland/wl_client.cpp +++ b/src/server/frontend_wayland/wl_client.cpp @@ -31,67 +31,9 @@ namespace msh = mir::shell; namespace { -static const int max_serial_event_pairs = 100; - -/// The context required for creating new WlClient's from wl_client*s -struct ConstructionCtx -{ - ConstructionCtx( - std::shared_ptr const& shell, - std::shared_ptr const& session_authorizer, - std::function&& client_created_callback) - : shell{shell}, - session_authorizer{session_authorizer}, - client_created_callback{std::make_unique>(std::move(client_created_callback))} - { - } - - wl_listener client_construction_listener; - wl_listener display_destruction_listener; - std::shared_ptr const shell; - std::shared_ptr const session_authorizer; - /// Needs to be a pointer so std::is_standard_layout passes - mir::StdLayoutUPtr> const client_created_callback; -}; - -static_assert( - std::is_standard_layout::value, - "ConstructionCtx must be standard layout for wl_container_of to be defined behaviour."); - -/// Intermediary between the wl_client* and WlClient -struct ClientCtx -{ - mf::WlClient* const client; - wl_listener destroy_listener; -}; - -static_assert( - std::is_standard_layout::value, - "ClientCtx must be standard layout for wl_container_of to be defined behaviour"); - -void cleanup_construction_ctx(wl_listener* listener, void*) -{ - ConstructionCtx* construction_context; - construction_context = wl_container_of(listener, construction_context, display_destruction_listener); - delete construction_context; -} +constexpr int max_serial_event_pairs = 100; } -void mf::WlClient::setup_new_client_handler( - wl_display* display, - std::shared_ptr const& shell, - std::shared_ptr const& session_authorizer, - std::function&& client_created_callback) -{ - auto context = new ConstructionCtx{shell, session_authorizer, std::move(client_created_callback)}; - - context->client_construction_listener.notify = &handle_client_created; - wl_display_add_client_created_listener(display, &context->client_construction_listener); - - // This handles deleting the ConstructionCtx we just created when the display is destoryed - context->display_destruction_listener.notify = &cleanup_construction_ctx; - wl_display_add_destroy_listener(display, &context->display_destruction_listener); -} mf::WlClient::~WlClient() { @@ -122,10 +64,9 @@ auto mf::WlClient::event_for(uint32_t serial) -> std::optional const& session, msh::Shell* shell) +mf::WlClient::WlClient(rust::Box client, std::shared_ptr const& session, msh::Shell* shell) : shell{shell}, - client{client}, - display{wl_client_get_display(client)}, + client{std::move(client)}, session{session} { } diff --git a/src/server/frontend_wayland/wl_client.h b/src/server/frontend_wayland/wl_client.h index 1e2f089dcf1..0fd32a9ace6 100644 --- a/src/server/frontend_wayland/wl_client.h +++ b/src/server/frontend_wayland/wl_client.h @@ -24,6 +24,8 @@ struct wl_display; #include #include #include +#include "wayland_rs/wayland_rs_cpp/include/wayland.h" +#include "wayland_rs/src/ffi.rs.h" #include @@ -31,6 +33,10 @@ struct MirEvent; namespace mir { +namespace wayland_rs +{ +class WaylandServer; +} namespace shell { class Shell; @@ -43,17 +49,8 @@ class SessionAuthorizer; class WlClient : public wayland::Client { public: - /// Initializes a ConstructionCtx that will create a WlClient for each wl_client created on the display. Should only - /// be called once per display. Destruction of the ConstructionCtx is handled automatically. - static void setup_new_client_handler( - wl_display* display, - std::shared_ptr const& shell, - std::shared_ptr const& session_authorizer, - std::function&& client_created_callback); - - ~WlClient(); - - auto raw_client() const -> wl_client* override { return client; } + WlClient(rust::Box client, std::shared_ptr const& session, shell::Shell* shell); + ~WlClient() override; auto is_being_destroyed() const -> bool override { return !owned_self; } @@ -67,15 +64,9 @@ class WlClient : public wayland::Client auto output_geometry_scale() -> float override { return output_geometry_scale_; } private: - WlClient(wl_client* client, std::shared_ptr const& session, shell::Shell* shell); - - static void handle_client_created(wl_listener* listener, void* data); - static void handle_client_destroyed(wl_listener* listener, void* data); - /// This shell is owned by the ClientSessionConstructor, which outlives all clients. shell::Shell* const shell; - wl_client* const client; - wl_display* const display; + rust::Box client; std::shared_ptr const session; std::shared_ptr owned_self; diff --git a/src/server/frontend_wayland/wl_client_registry.h b/src/server/frontend_wayland/wl_client_registry.h new file mode 100644 index 00000000000..99c38791f89 --- /dev/null +++ b/src/server/frontend_wayland/wl_client_registry.h @@ -0,0 +1,63 @@ +/* + * Copyright © Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef MIR_WL_CLIENT_REGISTRY_H +#define MIR_WL_CLIENT_REGISTRY_H + +#include "wayland_rs/src/ffi.rs.h" +#include +#include + +namespace mir +{ +namespace frontend +{ +class WlClient; + +/// A global registry of the connected Wayland clients. +/// +/// This interface bridges the gap between the [wayland_rs::WaylandClient] arriving +/// to us from Rust and the [WlClient] class in Mir which connects us to the shell +/// via [mir::shell::Session]. +class WlClientRegistry +{ +public: + WlClientRegistry(); + virtual ~WlClientRegistry() = default; + + WlClient* add_client(rust::Box client); + void delete_client(rust::Box client); + + /// Resolve a client from its opaque identifier. + /// + /// This may be `nullptr` if the identifier is not found. + WlClient* from_id(rust::Box client_id); + + /// Resolve a client from its raw client. + /// + /// This may be `nullptr` if the identifier is not found. + WlClient* from_client(rust::Box const& client); + +private: + WlClientRegistry(const WlClientRegistry&) = delete; + WlClientRegistry& operator=(const WlClientRegistry&) = delete; + + std::vector> clients; +}; +} +} + +#endif //MIR_WL_CLIENT_REGISTRY_H diff --git a/src/server/frontend_wayland/wl_pointer.cpp b/src/server/frontend_wayland/wl_pointer.cpp index 2653f499645..bffe9e71fc5 100644 --- a/src/server/frontend_wayland/wl_pointer.cpp +++ b/src/server/frontend_wayland/wl_pointer.cpp @@ -20,6 +20,7 @@ #include "wl_surface.h" #include "wl_seat.h" #include "relative-pointer-unstable-v1_wrapper.h" +#include "wayland_rs/src/ffi.rs.h" #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #include #include @@ -161,8 +161,8 @@ auto mf::WlPointer::linux_button_to_mir_button(int linux_button) -> std::optiona return std::nullopt; } -mf::WlPointer::WlPointer(wl_resource* new_resource) - : Pointer(new_resource, Version<9>()), +mf::WlPointer::WlPointer(rust::Box client) + : WlPointerImpl(std::move(client)), cursor{std::make_unique()} { } @@ -170,12 +170,18 @@ mf::WlPointer::WlPointer(wl_resource* new_resource) mf::WlPointer::~WlPointer() { if (surface_under_cursor) - surface_under_cursor.value().remove_destroy_listener(destroy_listener_id); + { + surface_under_cursor->with_value([&](auto& surface) + { + auto wl_surface = WlSurface::from(surface); + wl_surface->remove_destroy_listener(destroy_listener_id); + }); + } } -void mir::frontend::WlPointer::set_relative_pointer(mir::wayland::RelativePointerV1* relative_ptr) +void mir::frontend::WlPointer::set_relative_pointer(wayland_rs::Weak relative_ptr) { - relative_pointer = make_weak(relative_ptr); + relative_pointer = std::move(relative_ptr); } void mir::frontend::WlPointer::event(std::shared_ptr const& event, WlSurface& root_surface) @@ -210,11 +216,15 @@ void mf::WlPointer::leave(std::optional> { if (!surface_under_cursor) return; - surface_under_cursor.value().remove_destroy_listener(destroy_listener_id); - auto const serial = client->next_serial(event.value_or(nullptr)); - send_leave_event( - serial, - surface_under_cursor.value().raw_resource()); + surface_under_cursor.with_value([&](auto& surface) + { + auto const wl_surface = WlSurface::from(surface); + wl_surface->remove_destroy_listener(destroy_listener_id); + auto const serial = client->next_serial(event.value_or(nullptr)); + send_leave_event( + serial, + wl_surface->object_id()); + }); current_position = std::nullopt; // Don't clear current_buttons, their state can survive leaving and entering surfaces (note we currently have logic // to prevent changing surfaces while buttons are pressed, we wouldn't need to clear current_buttons regardless) diff --git a/src/server/frontend_wayland/wl_pointer.h b/src/server/frontend_wayland/wl_pointer.h index 86c7a076e76..f1365e808b2 100644 --- a/src/server/frontend_wayland/wl_pointer.h +++ b/src/server/frontend_wayland/wl_pointer.h @@ -17,12 +17,12 @@ #ifndef MIR_FRONTEND_WL_POINTER_H #define MIR_FRONTEND_WL_POINTER_H - -#include "wayland_wrapper.h" -#include +#include "wayland.h" +#include "wayland_rs/wayland_rs_cpp/include/relative_pointer_unstable_v1.h" #include #include #include +#include #include #include @@ -60,16 +60,16 @@ class CommitHandler CommitHandler& operator=(CommitHandler const&) = delete; }; -class WlPointer : public wayland::Pointer, private CommitHandler +class WlPointer : public wayland_rs::WlPointerImpl, private CommitHandler { public: static auto linux_button_to_mir_button(int linux_button) -> std::optional; - WlPointer(wl_resource* new_resource); + explicit WlPointer(rust::Box client); - ~WlPointer(); + ~WlPointer() override; - void set_relative_pointer(wayland::RelativePointerV1* relative_ptr); + void set_relative_pointer(wayland_rs::Weak relative_ptr); /// Convert the Mir event into Wayland events and send them to the client. root_surface is the one that received /// the Mir event, but the final Wayland event may be sent to a subsurface. @@ -78,6 +78,12 @@ class WlPointer : public wayland::Pointer, private CommitHandler struct Cursor; + void set_cursor(uint32_t serial, + wayland_rs::Weak const& surface, + bool has_surface, + int32_t hotspot_x, + int32_t hotspot_y) override; + private: void buttons(std::shared_ptr const& event); /// Returns true if any axis events were sent @@ -96,23 +102,14 @@ class WlPointer : public wayland::Pointer, private CommitHandler /// The cursor surface has committed void on_commit(WlSurface* surface) override; - /// Wayland request handlers - ///@{ - void set_cursor( - uint32_t serial, - std::optional const& surface, - int32_t hotspot_x, - int32_t hotspot_y) override; - ///@} - - wayland::Weak surface_under_cursor; + wayland_rs::Weak surface_under_cursor; std::optional enter_serial; wayland::DestroyListenerId destroy_listener_id; ///< ID of this pointer's destroy listener on surface_under_cursor bool needs_frame{false}; MirPointerButtons current_buttons{0}; std::optional current_position; std::unique_ptr cursor; - wayland::Weak relative_pointer; + wayland_rs::Weak relative_pointer; geometry::Displacement cursor_hotspot; }; diff --git a/src/server/frontend_wayland/wl_seat.cpp b/src/server/frontend_wayland/wl_seat.cpp index 5e9e71d65c7..f60e2efc111 100644 --- a/src/server/frontend_wayland/wl_seat.cpp +++ b/src/server/frontend_wayland/wl_seat.cpp @@ -43,6 +43,9 @@ #include #include +#include "mir/executor.h" +#include "wayland_rs/src/ffi.rs.h" + namespace mf = mir::frontend; namespace mi = mir::input; namespace ms = mir::scene; @@ -59,12 +62,12 @@ class mf::WlSeat::ListenerList ListenerList(ListenerList const&) = delete; ListenerList& operator=(ListenerList const&) = delete; - void register_listener(mw::Client* client, T* listener) + void register_listener(rust::Box const* client, T* listener) { listeners[client].push_back(listener); } - void unregister_listener(mw::Client* client, T const* listener) + void unregister_listener(rust::Box const* client, T const* listener) { std::vector& client_listeners = listeners[client]; client_listeners.erase( @@ -77,7 +80,7 @@ class mf::WlSeat::ListenerList listeners.erase(client); } - void for_each(mw::Client* client, std::function func) + void for_each(rust::Box const* client, std::function func) { for (auto listener: listeners[client]) func(listener); @@ -215,10 +218,14 @@ class mf::WlSeat::KeyboardObserver if (seat.focused_surface) { - seat.for_each_listener(seat.focused_surface.value().client, [&](WlKeyboard* keyboard) - { - keyboard->handle_event(event); - }); + seat.focused_surface.with_value([&](auto& surface) + { + rust::Box const* client = &surface.client; + seat.for_each_listener(client, [&](WlKeyboard* keyboard) + { + keyboard->handle_event(event); + }); + }); } } @@ -242,22 +249,19 @@ class mf::WlSeat::KeyboardObserver ConsumedKeyTracker consumed_key_tracker; }; -class mf::WlSeat::Instance : public wayland::Seat +class mf::WlSeat::Instance : public wayland_rs::WlSeatImpl { public: - Instance(wl_resource* new_resource, mf::WlSeat* seat); + Instance(rust::Box, mf::WlSeat* seat); mf::WlSeat* const seat; -private: - void get_pointer(wl_resource* new_pointer) override; - void get_keyboard(wl_resource* new_keyboard) override; - void get_touch(wl_resource* new_touch) override; + auto get_pointer() -> std::shared_ptr override; + auto get_keyboard() -> std::shared_ptr override; + auto get_touch() -> std::shared_ptr override; }; mf::WlSeat::WlSeat( - wl_display* display, - Executor& wayland_executor, std::shared_ptr const& clock, std::shared_ptr const& input_hub, std::shared_ptr> const& keyboard_observer_registrar, @@ -266,8 +270,7 @@ mf::WlSeat::WlSeat( std::shared_ptr const& surface_registry, std::shared_ptr const& input_trigger_registry, std::shared_ptr const& keyboard_state_tracker) - : Global(display, Version<9>()), - keymap{std::make_shared()}, + : keymap{std::make_shared()}, config_observer{ std::make_shared( keymap, @@ -287,7 +290,7 @@ mf::WlSeat::WlSeat( accessibility_manager{accessibility_manager} { input_hub->add_observer(config_observer); - keyboard_observer_registrar->register_interest(keyboard_observer, wayland_executor); + keyboard_observer_registrar->register_interest(keyboard_observer, immediate_executor); } mf::WlSeat::~WlSeat() @@ -306,17 +309,17 @@ auto mf::WlSeat::from(struct wl_resource* resource) -> WlSeat* return instance ? instance->seat : nullptr; } -void mf::WlSeat::for_each_listener(mw::Client* client, std::function func) +void mf::WlSeat::for_each_listener(rust::Box const* client, std::function func) { pointer_listeners->for_each(client, func); } -void mf::WlSeat::for_each_listener(mw::Client* client, std::function func) +void mf::WlSeat::for_each_listener(rust::Box const* client, std::function func) { keyboard_listeners->for_each(client, func); } -void mf::WlSeat::for_each_listener(mw::Client* client, std::function func) +void mf::WlSeat::for_each_listener(rust::Box const* client, std::function func) { touch_listeners->for_each(client, func); } @@ -333,14 +336,14 @@ auto mf::WlSeat::make_keyboard_helper(KeyboardCallbacks* callbacks) -> std::shar return keyboard_helper; } -void mf::WlSeat::bind(wl_resource* new_wl_seat) +auto mir::frontend::WlSeat::create(rust::Box client) -> std::shared_ptr { - new Instance{new_wl_seat, this}; + return std::make_shared(std::move(client), this); } void mf::WlSeat::set_focus_to(WlSurface* new_surface) { - auto const new_client = new_surface ? new_surface->client : nullptr; + auto const new_client = new_surface ? &new_surface->client : nullptr; if (new_client != focused_client) { keyboard_listeners->for_each(focused_client, [](WlKeyboard* keyboard) @@ -354,10 +357,13 @@ void mf::WlSeat::set_focus_to(WlSurface* new_surface) } if (focused_surface) { - focused_surface.value().remove_destroy_listener(focused_surface_destroy_listener_id); + focused_surface.with_value([&](auto& surface) + { + surface.remove_destroy_listener(focused_surface_destroy_listener_id); + }); } focused_client = new_client; - focused_surface = mw::make_weak(new_surface); + focused_surface = wayland_rs::Weak(new_surface); if (new_surface) { // This listener will be removed when either the focus changes or the seat is destroyed @@ -380,13 +386,26 @@ void mf::WlSeat::set_focus_to(WlSurface* new_surface) }); } -mf::WlSeat::Instance::Instance(wl_resource* new_resource, mf::WlSeat* seat) - : mw::Seat(new_resource, Version<9>()), +mf::WlSeat::Instance::Instance(rust::Box client, mf::WlSeat* seat) + : WlSeatImpl(std::move(client)), seat{seat} { // TODO: Read the actual capabilities. Do we have a keyboard? Mouse? Touch? send_capabilities_event(Capability::pointer | Capability::keyboard | Capability::touch); - send_name_event_if_supported("seat0"); + send_name_event("seat0"); +} + +auto mf::WlSeat::Instance::get_pointer() -> std::shared_ptr +{ + auto const pointer = std::make_shared(client->clone_box()); + auto dispatcher = std::make_shared(pointer); + seat->pointer_listeners->register_listener(&client, dispatcher.get()); + pointer->add_destroy_listener( + [listeners = seat->pointer_listeners, listener = std::move(dispatcher), client = client]() + { + listeners->unregister_listener(client, listener.get()); + }); + return pointer; } void mf::WlSeat::Instance::get_pointer(wl_resource* new_pointer) @@ -394,7 +413,7 @@ void mf::WlSeat::Instance::get_pointer(wl_resource* new_pointer) auto const pointer = new WlPointer{new_pointer}; auto dispatcher = std::make_shared(pointer); - seat->pointer_listeners->register_listener(client, dispatcher.get()); + seat->pointer_listeners->register_listener(&client, dispatcher.get()); pointer->add_destroy_listener( [listeners = seat->pointer_listeners, listener = std::move(dispatcher), client = client]() { @@ -425,7 +444,7 @@ void mf::WlSeat::Instance::get_touch(wl_resource* new_touch) }); } -void mf::WlSeat::add_focus_listener(mw::Client* client, FocusListener* listener) +void mf::WlSeat::add_focus_listener(rust::Box const* client, FocusListener* listener) { focus_listeners->register_listener(client, listener); if (focused_client == client) @@ -438,7 +457,7 @@ void mf::WlSeat::add_focus_listener(mw::Client* client, FocusListener* listener) } } -void mf::WlSeat::remove_focus_listener(mw::Client* client, FocusListener* listener) +void mf::WlSeat::remove_focus_listener(rust::Box const* client, FocusListener* listener) { focus_listeners->unregister_listener(client, listener); } diff --git a/src/server/frontend_wayland/wl_seat.h b/src/server/frontend_wayland/wl_seat.h index 7a7cb9d00c2..41b7f3cd737 100644 --- a/src/server/frontend_wayland/wl_seat.h +++ b/src/server/frontend_wayland/wl_seat.h @@ -17,9 +17,9 @@ #ifndef MIR_FRONTEND_WL_SEAT_H #define MIR_FRONTEND_WL_SEAT_H +#include "wayland.h" #include "input_trigger_registry.h" #include "wayland_wrapper.h" -#include #include @@ -61,23 +61,21 @@ class KeyboardStateTracker; class PointerEventDispatcher { public: - explicit PointerEventDispatcher(WlPointer* wl_pointer); + explicit PointerEventDispatcher(std::shared_ptr const& wl_pointer); void event(std::shared_ptr const& event, WlSurface& root_surface); void start_dispatch_to_data_device(WlDataDevice* wl_data_device); void stop_dispatch_to_data_device(); private: - wayland::Weak wl_pointer; + std::weak_ptr wl_pointer; wayland::Weak wl_data_device; }; -class WlSeat : public wayland::Seat::Global +class WlSeat { public: WlSeat( - wl_display* display, - Executor& wayland_executor, std::shared_ptr const& clock, std::shared_ptr const& input_hub, std::shared_ptr> const& keyboard_observer_registrar, @@ -96,9 +94,9 @@ class WlSeat : public wayland::Seat::Global static auto from(struct wl_resource* resource) -> WlSeat*; - void for_each_listener(wayland::Client* client, std::function func); - void for_each_listener(wayland::Client* client, std::function func); - void for_each_listener(wayland::Client* client, std::function func); + void for_each_listener(rust::Box const* client, std::function func); + void for_each_listener(rust::Box const* client, std::function func); + void for_each_listener(rust::Box const* client, std::function func); class FocusListener { @@ -118,14 +116,16 @@ class WlSeat : public wayland::Seat::Global auto make_keyboard_helper(KeyboardCallbacks* callbacks) -> std::shared_ptr; /// Adds the listener for future use, and makes a call into it to inform of initial state - void add_focus_listener(wayland::Client* client, FocusListener* listener); - void remove_focus_listener(wayland::Client* client, FocusListener* listener); + void add_focus_listener(rust::Box const* client, FocusListener* listener); + void remove_focus_listener(rust::Box const* client, FocusListener* listener); + + auto create(rust::Box client) -> std::shared_ptr; private: void set_focus_to(WlSurface* surface); - wayland::Client* focused_client{nullptr}; ///< Can be null - wayland::Weak focused_surface; + rust::Box* focused_client{nullptr}; ///< Can be null + wayland_rs::Weak focused_surface; wayland::DestroyListenerId focused_surface_destroy_listener_id{}; template @@ -151,8 +151,6 @@ class WlSeat : public wayland::Seat::Global std::shared_ptr const seat; std::shared_ptr const accessibility_manager; - - void bind(wl_resource* new_wl_seat) override; }; } } diff --git a/src/server/frontend_wayland/wl_subcompositor.cpp b/src/server/frontend_wayland/wl_subcompositor.cpp index 76b43ba81e2..28e8ca6ded1 100644 --- a/src/server/frontend_wayland/wl_subcompositor.cpp +++ b/src/server/frontend_wayland/wl_subcompositor.cpp @@ -18,72 +18,64 @@ #include "wl_subcompositor.h" #include "wl_surface.h" +#include "protocol_error.h" -#include -#include #include #include +#include "wayland_rs/src/ffi.rs.h" +#include "wayland_rs/wayland_rs_cpp/include/protocol_error.h" + namespace mf = mir::frontend; namespace geom = mir::geometry; -namespace mw = mir::wayland; - -namespace mir -{ -namespace frontend -{ -class WlSubcompositorInstance: wayland::Subcompositor -{ -public: - WlSubcompositorInstance(wl_resource* new_resource); - -private: - void get_subsurface(wl_resource* new_subsurface, wl_resource* surface, wl_resource* parent) override; -}; -} -} - -mf::WlSubcompositor::WlSubcompositor(wl_display* display) - : Global{display, Version<1>()} -{ -} - -void mf::WlSubcompositor::bind(wl_resource* new_wl_subcompositor) -{ - new WlSubcompositorInstance(new_wl_subcompositor); -} +namespace mw = mir::wayland_rs; -mf::WlSubcompositorInstance::WlSubcompositorInstance(wl_resource* new_resource) - : wayland::Subcompositor(new_resource, Version<1>()) +mf::WlSubcompositor::WlSubcompositor(rust::Box client) + : WlSubcompositorImpl(std::move(client)) { } -void mf::WlSubcompositorInstance::get_subsurface( - wl_resource* new_subsurface, - wl_resource* surface, - wl_resource* parent) +auto mf::WlSubcompositor::get_subsurface( + std::shared_ptr const& surface, + std::shared_ptr const& parent) + -> std::shared_ptr { - new WlSubsurface(new_subsurface, WlSurface::from(surface), WlSurface::from(parent)); + return std::make_shared(client->clone_box(), surface, parent); } -mf::WlSubsurface::WlSubsurface(wl_resource* new_subsurface, WlSurface* surface, WlSurface* parent_surface) - : wayland::Subsurface(new_subsurface, Version<1>()), +mf::WlSubsurface::WlSubsurface( + rust::Box client, + std::shared_ptr const& surface, + std::shared_ptr const& parent) + : wayland_rs::WlSubsurfaceImpl(std::move(client)), surface{surface}, - parent{parent_surface}, + parent{parent}, synchronized_{true} { - parent_surface->add_subsurface(this); - surface->set_role(this); - surface->pending_invalidate_surface_data(); + if (parent) + { + auto const wl_surface = WlSurface::from(*parent); + wl_surface->add_subsurface(this); + } + + auto const wl_surface = WlSurface::from(*surface); + wl_surface->set_role(this); + wl_surface->pending_invalidate_surface_data(); } mf::WlSubsurface::~WlSubsurface() { - if (parent) + if (auto const locked_parent = parent.lock()) { - parent.value().remove_subsurface(this); + auto const wl_surface = WlSurface::from(*locked_parent); + wl_surface->remove_subsurface(this); + } + + if (auto const locked_surface = surface.lock()) + { + auto const wl_surface = WlSurface::from(*locked_surface); + wl_surface->clear_role(); } - surface->clear_role(); refresh_surface_data_now(); } @@ -91,108 +83,140 @@ void mf::WlSubsurface::populate_surface_data(std::vector& input_shape_accumulator, geometry::Displacement const& parent_offset) const { - if (surface->buffer_size()) + if (auto const locked_surface = surface.lock()) { - // surface is mapped - surface->populate_surface_data(buffer_streams, input_shape_accumulator, parent_offset); + auto const wl_surface = WlSurface::from(*locked_surface); + if (wl_surface->buffer_size()) + { + // surface is mapped + wl_surface->populate_surface_data(buffer_streams, input_shape_accumulator, parent_offset); + } } } auto mf::WlSubsurface::total_offset() const -> geom::Displacement { - return parent ? - parent.value().offset() : - geom::Displacement{}; + if (auto const locked_parent = parent.lock()) + { + auto const wl_surface = WlSurface::from(*locked_parent); + return wl_surface->offset(); + } + + return geom::Displacement{}; } auto mf::WlSubsurface::synchronized() const -> bool { - bool const parent_synchronized = parent && parent.value().synchronized(); + bool parent_synchronized{false}; + if (auto const locked_parent = parent.lock()) + { + auto const wl_surface = WlSurface::from(*locked_parent); + parent_synchronized = wl_surface->synchronized(); + } return synchronized_ || parent_synchronized; } auto mf::WlSubsurface::scene_surface() const -> std::optional> { - return parent ? - parent.value().scene_surface() : - std::nullopt; + if (auto const locked_parent = parent.lock()) + { + auto const wl_surface = WlSurface::from(*locked_parent); + return wl_surface->scene_surface(); + } + + return std::nullopt; } void mf::WlSubsurface::parent_has_committed() { if (cached_state && synchronized()) { - surface->commit(cached_state.value()); + if (auto const locked_surface = surface.lock()) + { + auto const wl_surface = WlSurface::from(*locked_surface); + wl_surface->commit(cached_state.value()); + } cached_state = std::nullopt; } } auto mf::WlSubsurface::subsurface_at(geom::Point point) -> std::optional { - return surface->subsurface_at(point); + if (auto const locked_surface = surface.lock()) + { + auto const wl_surface = WlSurface::from(*locked_surface); + return wl_surface->subsurface_at(point); + } + return std::nullopt; } void mf::WlSubsurface::set_position(int32_t x, int32_t y) { - surface->set_pending_offset(geom::Displacement{x, y}); + if (auto const locked_surface = surface.lock()) + { + auto const wl_surface = WlSurface::from(*locked_surface); + wl_surface->set_pending_offset(geom::Displacement(x, y)); + } } -void mf::WlSubsurface::place_above(struct wl_resource* sibling) +void mf::WlSubsurface::place_above(std::shared_ptr const& sibling) { - if (!parent) + auto const locked_parent = parent.lock(); + if (!locked_parent) { // Parent has been destroyed, ignore return; } - WlSurface* sibling_surface = WlSurface::from(sibling); - - if (sibling_surface == surface) + if (sibling == surface.lock()) { BOOST_THROW_EXCEPTION(mw::ProtocolError( - resource, - mw::Subsurface::Error::bad_surface, + object_id(), + mw::WlSubsurfaceImpl::Error::bad_surface, "wl_subsurface.place_above: sibling cannot be the subsurface itself")); } - if (sibling_surface != &parent.value() && !parent.value().has_subsurface_with_surface(sibling_surface)) + auto parent_surface = WlSurface::from(*locked_parent); + auto sibling_surface = WlSurface::from(*sibling); + if (sibling != locked_parent && !parent_surface->has_subsurface_with_surface(sibling_surface)) { - BOOST_THROW_EXCEPTION(mw::ProtocolError( - resource, - mw::Subsurface::Error::bad_surface, + BOOST_THROW_EXCEPTION(wayland_rs::ProtocolError( + object_id(), + mw::WlSubsurfaceImpl::Error::bad_surface, "wl_subsurface.place_above: sibling must be the parent or a sibling subsurface")); } - parent.value().reorder_subsurface(this, sibling_surface, WlSurface::SubsurfacePlacement::above); + parent_surface->reorder_subsurface(this, sibling_surface, WlSurface::SubsurfacePlacement::above); } -void mf::WlSubsurface::place_below(struct wl_resource* sibling) +void mf::WlSubsurface::place_below(std::shared_ptr const& sibling) { - if (!parent) + auto const locked_parent = parent.lock(); + if (!locked_parent) { // Parent has been destroyed, ignore return; } - WlSurface* sibling_surface = WlSurface::from(sibling); - - if (sibling_surface == surface) + if (sibling == surface.lock()) { - BOOST_THROW_EXCEPTION(mw::ProtocolError( - resource, - mw::Subsurface::Error::bad_surface, + BOOST_THROW_EXCEPTION(wayland_rs::ProtocolError( + object_id(), + mw::WlSubsurfaceImpl::Error::bad_surface, "wl_subsurface.place_below: sibling cannot be the subsurface itself")); } - if (sibling_surface != &parent.value() && !parent.value().has_subsurface_with_surface(sibling_surface)) + auto parent_surface = WlSurface::from(*locked_parent); + auto sibling_surface = WlSurface::from(*sibling); + if (sibling != locked_parent && !parent_surface->has_subsurface_with_surface(sibling_surface)) { - BOOST_THROW_EXCEPTION(mw::ProtocolError( - resource, - mw::Subsurface::Error::bad_surface, + BOOST_THROW_EXCEPTION(wayland_rs::ProtocolError( + object_id(), + mw::WlSubsurfaceImpl::Error::bad_surface, "wl_subsurface.place_below: sibling must be the parent or a sibling subsurface")); } - parent.value().reorder_subsurface(this, sibling_surface, WlSurface::SubsurfacePlacement::below); + parent_surface->reorder_subsurface(this, sibling_surface, WlSurface::SubsurfacePlacement::below); } void mf::WlSubsurface::set_sync() @@ -207,9 +231,10 @@ void mf::WlSubsurface::set_desync() void mf::WlSubsurface::refresh_surface_data_now() { - if (parent) + if (auto const locked_parent = parent.lock()) { - parent.value().refresh_surface_data_now(); + auto wl_surface = WlSurface::from(*locked_parent); + wl_surface->refresh_surface_data_now(); } } @@ -222,7 +247,12 @@ void mf::WlSubsurface::commit(WlSurfaceState const& state) if (cached_state.value().buffer) { - bool const currently_mapped = static_cast(surface->buffer_size()); + bool currently_mapped{false}; + if (auto const locked_surface = surface.lock()) + { + auto const wl_surface = WlSurface::from(*locked_surface); + currently_mapped = static_cast(wl_surface->buffer_size()); + } bool const pending_mapped = cached_state.value().buffer.value(); if (currently_mapped != pending_mapped) { @@ -232,14 +262,23 @@ void mf::WlSubsurface::commit(WlSurfaceState const& state) if (synchronized()) { - if (cached_state.value().surface_data_needs_refresh() && parent) + if (cached_state.value().surface_data_needs_refresh()) { - parent.value().pending_invalidate_surface_data(); + if (auto const locked_parent = parent.lock()) + { + auto wl_surface = WlSurface::from(*locked_parent); + wl_surface->pending_invalidate_surface_data(); + } } } else { - surface->commit(cached_state.value()); + if (auto const locked_surface = surface.lock()) + { + auto const wl_surface = WlSurface::from(*locked_surface); + wl_surface->commit(cached_state.value()); + } + if (cached_state.value().surface_data_needs_refresh()) refresh_surface_data_now(); cached_state = std::nullopt; @@ -248,17 +287,9 @@ void mf::WlSubsurface::commit(WlSurfaceState const& state) void mf::WlSubsurface::surface_destroyed() { - if (!client->is_being_destroyed()) + if (surface.expired()) { - // "When a client wants to destroy a wl_surface, they must destroy this 'role object' wl_surface" BOOST_THROW_EXCEPTION(std::runtime_error{ - "wl_surface@" + std::to_string(wl_resource_get_id(surface->resource)) + - " destroyed before it's associated wl_subsurface@" + std::to_string(wl_resource_get_id(resource))}); - } - else - { - // If the client has been destroyed, everything is getting cleaned up in an arbitrary order. Delete this so our - // derived class doesn't end up using the now-defunct surface. - delete this; + "wl_surface destroyed before it's associated wl_subsurface@" + std::to_string(object_id())}); } } diff --git a/src/server/frontend_wayland/wl_subcompositor.h b/src/server/frontend_wayland/wl_subcompositor.h index 9f00c7aeb7f..adc62fbb6dd 100644 --- a/src/server/frontend_wayland/wl_subcompositor.h +++ b/src/server/frontend_wayland/wl_subcompositor.h @@ -17,9 +17,9 @@ #ifndef MIR_FRONTEND_WL_SUBSURFACE_H #define MIR_FRONTEND_WL_SUBSURFACE_H -#include "wayland_wrapper.h" #include "wl_surface_role.h" #include "wl_surface.h" +#include "wayland.h" #include #include @@ -40,19 +40,21 @@ namespace frontend class WlSurface; class WlSubcompositorInstance; -class WlSubcompositor : wayland::Subcompositor::Global +class WlSubcompositor : public wayland_rs::WlSubcompositorImpl { public: - WlSubcompositor(wl_display* display); - -private: - void bind(wl_resource* new_wl_subcompositor); + explicit WlSubcompositor(rust::Box client); + auto get_subsurface(std::shared_ptr const& surface, std::shared_ptr const& parent) + -> std::shared_ptr override; }; -class WlSubsurface: public WlSurfaceRole, wayland::Subsurface +class WlSubsurface: public WlSurfaceRole, public wayland_rs::WlSubsurfaceImpl { public: - WlSubsurface(wl_resource* new_subsurface, WlSurface* surface, WlSurface* parent_surface); + WlSubsurface( + rust::Box client, + std::shared_ptr const& surface, + std::shared_ptr const& parent); ~WlSubsurface(); void populate_surface_data(std::vector& buffer_streams, @@ -67,12 +69,12 @@ class WlSubsurface: public WlSurfaceRole, wayland::Subsurface auto subsurface_at(geometry::Point point) -> std::optional; - WlSurface* get_surface() const { return surface; } + std::shared_ptr get_surface() const { return surface.lock(); } private: + void place_above(std::shared_ptr const& sibling) override; + void place_below(std::shared_ptr const& sibling) override; void set_position(int32_t x, int32_t y) override; - void place_above(struct wl_resource* sibling) override; - void place_below(struct wl_resource* sibling) override; void set_sync() override; void set_desync() override; @@ -80,9 +82,8 @@ class WlSubsurface: public WlSurfaceRole, wayland::Subsurface virtual void commit(WlSurfaceState const& state) override; void surface_destroyed() override; - WlSurface* const surface; - /// This class is responsible for removing itself from the parent's children list when needed - wayland::Weak const parent; + std::weak_ptr const surface; + std::weak_ptr const parent; bool synchronized_; std::optional cached_state; }; diff --git a/src/server/frontend_wayland/wl_surface.cpp b/src/server/frontend_wayland/wl_surface.cpp index 08cbada45d6..9fb21049a1e 100644 --- a/src/server/frontend_wayland/wl_surface.cpp +++ b/src/server/frontend_wayland/wl_surface.cpp @@ -55,6 +55,9 @@ #include #include +#include "wl_client.h" +#include "wl_client_registry.h" + namespace mf = mir::frontend; namespace geom = mir::geometry; namespace mw = mir::wayland; @@ -114,12 +117,13 @@ bool mf::WlSurfaceState::surface_data_needs_refresh() const } mf::WlSurface::WlSurface( - wl_resource* new_resource, + rust::Box client, + std::shared_ptr const& registry, std::shared_ptr const& wayland_executor, std::shared_ptr const& frame_callback_executor, std::shared_ptr const& allocator) - : Surface(new_resource, Version<6>()), - session{client->client_session()}, + : WlSurfaceImpl(std::move(client)), + session{registry->from_client(WlSurfaceImpl::client)->client_session()}, stream{session->create_buffer_stream({{}, mir_pixel_format_invalid, graphics::BufferUsage::undefined})}, allocator{allocator}, wayland_executor{wayland_executor}, @@ -347,10 +351,9 @@ void mf::WlSurface::populate_surface_data(std::vector(static_cast(raw_surface)); + return static_cast(&impl); } void mf::WlSurface::send_frame_callbacks(CallbackList& list) diff --git a/src/server/frontend_wayland/wl_surface.h b/src/server/frontend_wayland/wl_surface.h index c1f0c228a53..775cdac054c 100644 --- a/src/server/frontend_wayland/wl_surface.h +++ b/src/server/frontend_wayland/wl_surface.h @@ -21,8 +21,10 @@ #include #include "wayland_wrapper.h" #include +#include #include "wl_surface_role.h" +#include "wayland_rs/wayland_rs_cpp/include/wayland.h" #include #include @@ -65,6 +67,7 @@ class WlSubsurface; class ResourceLifetimeTracker; class Viewport; class SyncTimeline; +class WlClientRegistry; struct WlSurfaceState { @@ -119,15 +122,15 @@ class NullWlSurfaceRole : public WlSurfaceRole WlSurface* const surface; }; -class WlSurface : public wayland::Surface +class WlSurface : public wayland_rs::WlSurfaceImpl { public: - WlSurface(wl_resource* new_resource, - std::shared_ptr const& wayland_executor, + WlSurface(rust::Box client, + std::shared_ptr const& registry, std::shared_ptr const& frame_callback_executor, std::shared_ptr const& allocator); - ~WlSurface(); + ~WlSurface() override; using SceneSurfaceCreatedCallback = std::function)>; @@ -136,7 +139,6 @@ class WlSurface : public wayland::Surface std::optional buffer_size() const { return buffer_size_; } bool synchronized() const; auto subsurface_at(geometry::Point point) -> std::optional; - wl_resource* raw_resource() const { return resource; } auto scene_surface() const -> std::optional>; /// Callback is called immediately if the surface already has a scene::Surface, or else on the first commit where /// one exists @@ -193,7 +195,18 @@ class WlSurface : public wayland::Surface std::shared_ptr const session; std::shared_ptr const stream; - static WlSurface* from(wl_resource* resource); + static WlSurface* from(WlSurfaceImpl& impl); + + void attach(wayland_rs::Weak const& buffer, bool has_buffer, int32_t x, int32_t y) override; + void damage(int32_t x, int32_t y, int32_t width, int32_t height) override; + auto frame() -> std::shared_ptr override; + void set_opaque_region(wayland_rs::Weak const& region, bool has_region) override; + void set_input_region(wayland_rs::Weak const& region, bool has_region) override; + void commit() override; + void damage_buffer(int32_t x, int32_t y, int32_t width, int32_t height) override; + void set_buffer_transform(uint32_t transform) override; + void set_buffer_scale(int32_t scale) override; + void offset(int32_t x, int32_t y) override; private: std::shared_ptr const allocator; @@ -242,17 +255,6 @@ class WlSurface : public wayland::Surface void send_frame_callbacks(CallbackList& list); - void attach(std::optional const& buffer, int32_t x, int32_t y) override; - void damage(int32_t x, int32_t y, int32_t width, int32_t height) override; - void frame(wl_resource* callback) override; - void set_opaque_region(std::optional const& region) override; - void set_input_region(std::optional const& region) override; - void commit() override; - void damage_buffer(int32_t x, int32_t y, int32_t width, int32_t height) override; - void set_buffer_transform(int32_t transform) override; - void set_buffer_scale(int32_t scale) override; - void offset(int32_t x, int32_t y) override; - std::optional opaque_region_; }; } diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt deleted file mode 100644 index 5ad3bc6cd67..00000000000 --- a/src/wayland/CMakeLists.txt +++ /dev/null @@ -1,82 +0,0 @@ -set(MIRWAYLAND_ABI 5) -set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map) -add_compile_definitions(MIR_LOG_COMPONENT_FALLBACK="mirwayland") - -add_subdirectory(generator/) - -set(STANDARD_SOURCES - lifetime_tracker.cpp - resource.cpp - global.cpp - protocol_error.cpp - client.cpp -) - -add_library(mirwayland SHARED - ${STANDARD_SOURCES} -) - -mir_generate_protocol_wrapper(mirwayland "wl_" wayland.xml) -mir_generate_protocol_wrapper(mirwayland "z" xdg-shell-unstable-v6.xml) -mir_generate_protocol_wrapper(mirwayland "" xdg-shell.xml) -mir_generate_protocol_wrapper(mirwayland "z" xdg-output-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwlr_" wlr-layer-shell-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwlr_" wlr-foreign-toplevel-management-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" pointer-constraints-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" relative-pointer-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" virtual-keyboard-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" text-input-unstable-v3.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" text-input-unstable-v2.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" text-input-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" input-method-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" input-method-unstable-v2.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" idle-inhibit-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwp_" primary-selection-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "z" wlr-screencopy-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zwlr_" wlr-virtual-pointer-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "ext_" ext-session-lock-v1.xml) -mir_generate_protocol_wrapper(mirwayland "zmir_" mir-shell-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "z" xdg-decoration-unstable-v1.xml) -mir_generate_protocol_wrapper(mirwayland "wp_" viewporter.xml) -mir_generate_protocol_wrapper(mirwayland "wp_" fractional-scale-v1.xml) -mir_generate_protocol_wrapper(mirwayland "z" xdg-activation-v1.xml) -mir_generate_protocol_wrapper(mirwayland "wp_" linux-drm-syncobj-v1.xml) -mir_generate_protocol_wrapper(mirwayland "ext_" ext-data-control-v1.xml) -# We don't strip the "ext_" prefix here, because it would conflict -# with wlr-foreign-toplevel-management-unstable-v1. -mir_generate_protocol_wrapper(mirwayland "" ext-foreign-toplevel-list-v1.xml) -mir_generate_protocol_wrapper(mirwayland "ext_" ext-image-capture-source-v1.xml) -mir_generate_protocol_wrapper(mirwayland "ext_" ext-image-copy-capture-v1.xml) -mir_generate_protocol_wrapper(mirwayland "ext_" ext-input-trigger-registration-v1.xml) -mir_generate_protocol_wrapper(mirwayland "ext_" ext-input-trigger-action-v1.xml) - -target_link_libraries(mirwayland - PUBLIC - mircore - PkgConfig::WAYLAND_SERVER - PRIVATE - mircommon -) - -target_include_directories(mirwayland - PUBLIC - ${PROJECT_SOURCE_DIR}/include/wayland - ${CMAKE_CURRENT_BINARY_DIR} -) - -set_target_properties(mirwayland - PROPERTIES - SOVERSION ${MIRWAYLAND_ABI} - LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" - LINK_DEPENDS ${symbol_map} -) - -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/mirwayland.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/mirwayland.pc - @ONLY -) - -install(TARGETS mirwayland LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mirwayland.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") -install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/wayland/mir DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/mirwayland") diff --git a/src/wayland/client.cpp b/src/wayland/client.cpp deleted file mode 100644 index 12518670380..00000000000 --- a/src/wayland/client.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#include -#include - -namespace mw = mir::wayland; - -namespace -{ -/// All operations for the same display should happen on the same thread, but since in theory a single process could -/// manage multiple Wayland displays, best to keep global state threadsafe. -mir::Synchronised>>> client_map; -} - -auto mw::Client::from(wl_client const* client) -> Client& -{ - return *shared_from(client); -} - -void mw::Client::register_client(wl_client const* raw, std::shared_ptr const& shared) -{ - client_map.lock()->push_back({raw, shared}); -} - -void mw::Client::unregister_client(wl_client const* raw) -{ - auto const map = client_map.lock(); - std::erase_if(*map, [&](auto const& item){ return item.first == raw; }); -} - -auto mw::Client::shared_from(wl_client const* client) -> std::shared_ptr -{ - auto const locked = client_map.lock(); - for (auto& [wlc, wmc] : *locked) - { - if (wlc == client) - { - if (auto const shared = wmc.lock()) - { - return shared; - } - else - { - // The client should remove itself from the map in it's destructor and should be destroyed/accessed on a - // single thread, so this should never happen - mir::fatal_error("client_map has stale entry for wl_client %p", static_cast(client)); - } - } - } - mir::fatal_error("wl_client %p is %s", static_cast(client), client ? "unknown" : "null"); - abort(); // Make compiler happy -} diff --git a/src/wayland/generator/CMakeLists.txt b/src/wayland/generator/CMakeLists.txt deleted file mode 100644 index e4f3278f8f0..00000000000 --- a/src/wayland/generator/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -pkg_check_modules(XMLPP libxml++-2.6 REQUIRED IMPORTED_TARGET) - -add_executable(mir_wayland_generator - wrapper_generator.cpp - utils.cpp utils.h - enum.cpp enum.h - argument.cpp argument.h - method.cpp method.h - request.cpp request.h - event.cpp event.h - interface.cpp interface.h - global.cpp global.h - emitter.cpp emitter.h -) - -target_link_libraries(mir_wayland_generator - PkgConfig::XMLPP -) - -install(TARGETS mir_wayland_generator - DESTINATION ${CMAKE_INSTALL_BINDIR} -) diff --git a/src/wayland/generator/argument.cpp b/src/wayland/generator/argument.cpp deleted file mode 100644 index 1a9f089c852..00000000000 --- a/src/wayland/generator/argument.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "argument.h" -#include "utils.h" - -#include - -#include - -namespace -{ - -Emitter fd_wl2mir(Argument const* me) -{ - return Line{"mir::Fd ", me->name, "_resolved{", me->name, "};"}; -} - -Emitter fd_mir2wl(Argument const* me) -{ - return Line{"int32_t ", me->name, "_resolved{", me->name, "};"}; -} - -Emitter new_id_wl2mir(Argument const* me) -{ - return Lines{ - {"wl_resource* ", me->name, "_resolved{"}, - {Emitter::layout({ - "wl_resource_create(client, ", me->object_type_fragment(), ", wl_resource_get_version(resource), ", me->name, ")" - }, true, false, Emitter::single_indent), "};"}, - {"if (", me->name, "_resolved == nullptr)"}, - Block{ - "wl_client_post_no_memory(client);", - "BOOST_THROW_EXCEPTION((std::bad_alloc{}));", - } - }; -} - -Emitter fixed_wl2mir(Argument const* me) -{ - return Line{"double ", me->name, "_resolved{wl_fixed_to_double(", me->name, ")};"}; -} - -Emitter fixed_mir2wl(Argument const* me) -{ - return Line{"wl_fixed_t ", me->name, "_resolved{wl_fixed_from_double(", me->name, ")};"}; -} - -Emitter string_mir2wl(Argument const* me) -{ - return Lines{ - {"const char* ", me->name, "_resolved = ", me->name, ".c_str();"} - }; -} - -Emitter optional_object_wl2mir(Argument const* me) -{ - return Lines{ - {"std::optional ", me->name, "_resolved;"}, - {"if (", me->name, " != nullptr)"}, - Block{ - {me->name, "_resolved = {", me->name, "};"} - } - }; -} - -Emitter optional_object_mir2wl(Argument const* me) -{ - return Lines{ - {"struct wl_resource* ", me->name, "_resolved = nullptr;"}, - {"if (", me->name, ")"}, - Block{ - {me->name, "_resolved = ", me->name, ".value();"} - } - }; -} - -Emitter optional_string_wl2mir(Argument const* me) -{ - return Lines{ - {"std::optional ", me->name, "_resolved;"}, - {"if (", me->name, " != nullptr)"}, - Block{ - {me->name, "_resolved = {", me->name, "};"} - } - }; -} - -Emitter optional_string_mir2wl(Argument const* me) -{ - return Lines{ - {"const char* ", me->name, "_resolved = nullptr;"}, - {"if (", me->name, ")"}, - Block{ - {me->name, "_resolved = ", me->name, ".value().c_str();"} - } - }; -} - -std::unordered_map const request_type_map = { - { "uint", { "uint32_t", "uint32_t", "u", {} }}, - { "int", { "int32_t", "int32_t", "i", {} }}, - { "fd", { "mir::Fd", "int32_t", "h", { fd_wl2mir } }}, - { "object", { "struct wl_resource*", "struct wl_resource*", "o", {} }}, - { "string", { "std::string const&", "char const*", "s", {} }}, - { "new_id", { "struct wl_resource*", "uint32_t", "n", {new_id_wl2mir} }}, - { "fixed", { "double", "wl_fixed_t", "f", { fixed_wl2mir } }}, - { "array", { "struct wl_array*", "struct wl_array*", "a", {} }} -}; - -std::unordered_map const request_optional_type_map = { - { "object", { "std::optional const&", "struct wl_resource*", "?o", { optional_object_wl2mir } }}, - { "string", { "std::optional const&", "char const*", "?s",{ optional_string_wl2mir } }}, -}; - -std::unordered_map const event_type_map = { - { "uint", { "uint32_t", "uint32_t", "u", {} }}, - { "int", { "int32_t", "int32_t", "i", {} }}, - { "fd", { "mir::Fd", "int32_t", "h", { fd_mir2wl } }}, - { "object", { "struct wl_resource*", "struct wl_resource*", "o", {} }}, - { "string", { "std::string const&", "char const*", "s", { string_mir2wl } }}, - { "new_id", { "struct wl_resource*", "struct wl_resource*", "n", {} }}, - { "fixed", { "double", "wl_fixed_t", "f", { fixed_mir2wl } }}, - { "array", { "struct wl_array*", "struct wl_array*", "a", {} }} -}; - -std::unordered_map const event_optional_type_map = { - { "object", { "std::optional const&", "struct wl_resource*", "?o", {optional_object_mir2wl} }}, - { "string", { "std::optional const&", "char const*", "?s", { optional_string_mir2wl } }}, -}; -} - -Argument::Argument(xmlpp::Element const& node, bool is_event) - : name{sanitize_name(node.get_attribute_value("name"))}, - interface{get_interface(node)}, - descriptor{get_type(node, is_event)} -{ -} - -Emitter Argument::wl_prototype() const -{ - return {descriptor.wl_type, " ", name}; -} - -Emitter Argument::mir_prototype() const -{ - return {descriptor.mir_type, " ", name}; -} - -Emitter Argument::call_fragment() const -{ - return descriptor.converter ? (name + "_resolved") : name; -} - -Emitter Argument::object_type_fragment() const -{ - if (interface) - return {"&", interface.value(), "_interface_data"}; - else - return nullptr; -} - -Emitter Argument::type_str_fragment() const -{ - return descriptor.wl_type_abbr; -} - -std::optional Argument::converter() const -{ - if (descriptor.converter) - return descriptor.converter.value()(this); - else - return std::nullopt; -} - -void Argument::populate_required_interfaces(std::set& interfaces) const -{ - if (interface) - interfaces.insert(interface.value()); -} - -Argument::TypeDescriptor Argument::get_type(xmlpp::Element const& node, bool is_event) -{ - bool is_optional = false; - if (auto allow_null = node.get_attribute("allow-null")) - is_optional = (allow_null->get_value() == "true"); - std::string type = node.get_attribute_value("type"); - - try - { - if (is_optional) - { - if (is_event) - { - return event_optional_type_map.at(type); - } - else - { - return request_optional_type_map.at(type); - } - } - else - { - if (is_event) - { - return event_type_map.at(type); - } - else - { - return request_type_map.at(type); - } - } - } - catch (std::out_of_range const&) - { - // its an error message, so who cares about the memory leak? - return TypeDescriptor{"unknown_type_" + type, "unknown_type_" + type, "!", - {[=](Argument const* me) -> Emitter - { - return Lines{ - {"#error '", me->name, "' is of type '" + type + "' (which is unknown for a", is_event ? "n event" : " request", is_optional ? " optional" : "", ")"}, - {"#error type resolving code can be found in argument.cpp in the wayland scanner"} - }; - }}}; - } -} - -std::optional Argument::get_interface(xmlpp::Element const& node) -{ - std::string ret = node.get_attribute_value("interface"); - if (ret.empty()) - return std::nullopt; - else - return {ret}; -} diff --git a/src/wayland/generator/argument.h b/src/wayland/generator/argument.h deleted file mode 100644 index 612cb3d5da6..00000000000 --- a/src/wayland/generator/argument.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_ARGUMENT_H -#define MIR_WAYLAND_GENERATOR_ARGUMENT_H - -#include "emitter.h" - -#include -#include -#include -#include - -namespace xmlpp -{ -class Element; -} - -class Argument -{ -public: - struct TypeDescriptor - { - std::string mir_type; - std::string wl_type; - std::string wl_type_abbr; // abbreviated type (i for int, etc), used by libwayland - std::optional> converter; - }; - - Argument(xmlpp::Element const& node, bool is_event); - - Emitter wl_prototype() const; - Emitter mir_prototype() const; - Emitter call_fragment() const; - Emitter object_type_fragment() const; - Emitter type_str_fragment() const; - std::optional converter() const; - - void populate_required_interfaces(std::set& interfaces) const; // fills the set with interfaces used - - std::string const name; - std::optional const interface; -private: - static TypeDescriptor get_type(xmlpp::Element const& node, bool is_event); - static std::optional get_interface(xmlpp::Element const& node); - - TypeDescriptor descriptor; -}; - -#endif // MIR_WAYLAND_GENERATOR_ARGUMENT_H diff --git a/src/wayland/generator/emitter.cpp b/src/wayland/generator/emitter.cpp deleted file mode 100644 index c255af3e255..00000000000 --- a/src/wayland/generator/emitter.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "emitter.h" - -std::string const Emitter::single_indent = " "; -Emitter const Emitter::null{std::shared_ptr(nullptr)}; - -class Emitter::Impl -{ -public: - Impl() = default; - virtual ~Impl() = default; - - virtual void emit(State state) const = 0; -}; - -class EmptyLineEmitter : public Emitter::Impl -{ -public: - EmptyLineEmitter() = default; - virtual ~EmptyLineEmitter() = default; - - void emit(Emitter::State state) const override - { - if (!*state.on_fresh_line) - state.out << "\n"; - state.out << "\n"; - *state.on_fresh_line = true; - } -}; - -class StringEmitter : public Emitter::Impl -{ -public: - StringEmitter(std::string text) - : text{text} - { - } - - virtual ~StringEmitter() = default; - - void emit(Emitter::State state) const override - { - if (*state.on_fresh_line) // if on a fresh line, we may need to indent - { - if (text.size() > 0 && text[0] != '#') // if this is a preprocessor line don't indent - state.out << state.indent; - } - state.out << text; - *state.on_fresh_line = false; - } - -private: - std::string const text; -}; - -class SeqEmitter : public Emitter::Impl -{ -public: - SeqEmitter(std::vector const& children, Emitter const& delimiter = nullptr, bool at_start = false, bool at_end = false) - : children(children), - delimiter{delimiter}, - at_start{at_start}, - at_end{at_end} - { - } - - virtual ~SeqEmitter() = default; - - void emit(Emitter::State state) const override - { - if (at_start) - delimiter.emit(state); - bool is_start = true; - for (auto& i: children) - { - if (delimiter.is_valid() && !is_start) - delimiter.emit(state); - is_start = false; - i.emit(state); - } - if (at_end) - delimiter.emit(state); - } - -private: - std::vector const children; - Emitter const delimiter; - bool const at_start; - bool const at_end; -}; - -class LayoutEmitter : public Emitter::Impl -{ -public: - LayoutEmitter(Emitter const& child, bool clear_line_before = true, bool clear_line_after = true, std::string indent="") - : child{std::move(child)}, - clear_line_before{clear_line_before}, - clear_line_after{clear_line_after}, - indent{indent} - { - } - - virtual ~LayoutEmitter() = default; - - void emit(Emitter::State state) const override - { - state.indent += indent; - if (clear_line_before && !*state.on_fresh_line) - { - state.out << "\n"; - *state.on_fresh_line = true; - } - child.emit(state); - if (clear_line_after && !*state.on_fresh_line) - { - state.out << "\n"; - *state.on_fresh_line = true; - } - } - -private: - Emitter const child; - bool const clear_line_before; - bool const clear_line_after; - std::string const indent; -}; - -std::shared_ptr Emitter::string(std::string text) -{ - if (text.empty()) - return {}; - else - return std::make_shared(text); -} - -std::shared_ptr Emitter::seq(std::vector const& children, - Emitter const& delimiter, - bool at_start, - bool at_end) -{ - std::vector valid; - for (auto const& i : children) - { - if (i.is_valid()) - valid.push_back(i); - } - if (valid.empty()) - return {}; - else - return std::make_shared(std::move(valid), delimiter, at_start, at_end); -} - -std::shared_ptr Emitter::layout(Emitter const& child, - bool clear_line_before, - bool clear_line_after, - std::string indent) -{ - if (clear_line_before == false && clear_line_after == false && indent == "") - return child.impl; - else - return std::make_shared(child, clear_line_before, clear_line_after, indent); -} - -Emitter::Emitter(std::string const& text) : impl{string(text)} {} -Emitter::Emitter(const char* text) : impl{text == nullptr ? nullptr : string(text)} {} -Emitter::Emitter(std::initializer_list emitters) : impl{seq(emitters)} {} -Emitter::Emitter(std::vector const& emitters) : impl{seq(emitters)} {} - -void Emitter::emit(State state) const -{ - if (impl) - { - impl->emit(state); - } -} - -Emitter::Emitter(std::shared_ptr impl) - : impl{std::move(impl)} -{ -} - -Emitter const empty_line = Emitter{std::make_shared()}; diff --git a/src/wayland/generator/emitter.h b/src/wayland/generator/emitter.h deleted file mode 100644 index 6ab1a90b17c..00000000000 --- a/src/wayland/generator/emitter.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_EMITTER_H -#define MIR_WAYLAND_GENERATOR_EMITTER_H - -#include -#include -#include -#include - -class Emitter -{ -public: - // is used by emit method - struct State - { - State(std::ostream& out) - : out{out}, - on_fresh_line{std::make_shared(true)}, - indent{""} - { - } - - std::ostream& out; - std::shared_ptr const on_fresh_line; - std::string indent; - }; - - Emitter() = delete; - - class Impl; - - // explicit low level constructors - static std::shared_ptr string(std::string text); - static std::shared_ptr seq(std::vector const& children, - Emitter const& delimiter = Emitter::null, - bool at_start = false, - bool at_end = false); - static std::shared_ptr layout(Emitter const& child, - bool clear_line_before, - bool clear_line_after, - std::string indent = ""); - - // constructors for simple emitters - Emitter(std::shared_ptr impl); - Emitter(std::string const& text); - Emitter(const char* text); - Emitter(std::initializer_list emitters); - explicit Emitter(std::vector const& emitters); - - void emit(State state) const; - bool is_valid() const { return impl != nullptr; } - - static Emitter const null; - static std::string const single_indent; - -private: - - std::shared_ptr impl; -}; - -Emitter const extern empty_line; - -// a line that is at the same indentation level as surrounding block -// implicitly convertible to an Emitter -struct Line -{ - Line(std::initializer_list emitters) : emitters{emitters} {} - Line(std::initializer_list emitters, bool break_before, bool break_after, std::string indent = "") - : emitters{emitters}, - break_before{break_before}, - break_after{break_after}, - indent{indent} - { - } - - inline operator Emitter() const - { - return Emitter::layout(Emitter{emitters}, break_before, break_after, indent); - } - -private: - std::vector const emitters; - bool const break_before{true}; - bool const break_after{true}; - std::string const indent; -}; - -// a series of lines that is at the same indentation level as surrounding block -// implicitly convertible to an Emitter -struct Lines -{ - explicit Lines(std::initializer_list emitters) : emitters{std::vector(emitters)} {} - explicit Lines(std::vector const& emitters) : emitters{emitters} {} - - inline operator Emitter() const - { - std::vector l; - for (auto const& i : emitters) - { - l.push_back(Emitter::layout(i, true, true)); - } - return Emitter{l}; - } - -private: - std::vector const emitters; -}; - -// an indented curly brace surrounded block -// implicitly convertible to an Emitter -struct Block -{ - explicit Block(std::initializer_list emitters) : emitters{std::vector(emitters)} {} - explicit Block(std::vector const& emitters) : emitters{emitters} {} - - inline operator Emitter() const - { - return Emitter::layout({ - "{", - Emitter::layout( - Lines{emitters}, - true, - true, - Emitter::single_indent), - "}"}, - true, - false); - } - -private: - std::vector const emitters; -}; - -struct EmptyLineList -{ - explicit EmptyLineList(std::initializer_list items) - : items{std::vector(items)} - { - } - - explicit EmptyLineList(std::vector items) - : items{items} - { - } - - inline operator Emitter() const { - return Emitter::seq(items, empty_line); - } - -private: - std::vector const items; -}; - -struct BraceList -{ - explicit BraceList(std::initializer_list items) - : items{std::vector(items)} - { - } - - explicit BraceList(std::vector items) - : items{items} - { - } - - inline operator Emitter() const { - return Emitter::layout({ - "{", - Emitter::layout( - Emitter::seq( - items, - Emitter::layout( - ",", - false, - true)), - true, - false, - Emitter::single_indent), - "};" - }, - false, - true); - } - -private: - std::vector const items; -}; - -#endif // MIR_WAYLAND_GENERATOR_EMITTER_H diff --git a/src/wayland/generator/enum.cpp b/src/wayland/generator/enum.cpp deleted file mode 100644 index 9ea82adebdf..00000000000 --- a/src/wayland/generator/enum.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "enum.h" -#include "utils.h" - -#include - -Enum::Enum(xmlpp::Element const& node, std::string const& class_name) - : name{sanitize_name(to_camel_case(node.get_attribute_value("name")))}, - class_name{class_name} -{ - for (auto const& child : node.get_children("entry")) - { - auto entry_node = dynamic_cast(child); - std::string entry_name = sanitize_name(entry_node->get_attribute_value("name")); - std::string entry_value_str = entry_node->get_attribute_value("value"); - entries.emplace_back(Entry{entry_name, entry_value_str}); - } -} - -Emitter Enum::declaration() const -{ - std::vector body; - for (auto const& entry : entries) - { - body.push_back({"static uint32_t const ", entry.name, " = ", entry.value, ";"}); - } - - return Lines{ - {"struct ", name}, - {Block{ - body - }, ";"} - }; -} - -Emitter Enum::impl() const -{ - std::vector lines; - for (auto const& entry : entries) - { - lines.push_back({"uint32_t const mw::", class_name, "::", name, "::", entry.name, ";"}); - } - - return Lines{lines}; -} diff --git a/src/wayland/generator/enum.h b/src/wayland/generator/enum.h deleted file mode 100644 index f65174bf676..00000000000 --- a/src/wayland/generator/enum.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_ENUM_H -#define MIR_WAYLAND_GENERATOR_ENUM_H - -#include "emitter.h" - -namespace xmlpp -{ -class Element; -} - -class Enum -{ -public: - struct Entry - { - std::string name; - std::string value; - }; - - Enum(xmlpp::Element const& node, std::string const& class_name); - - Emitter declaration() const; - Emitter impl() const; - -private: - std::string const name; - std::string const class_name; - std::vector entries; -}; - -#endif // MIR_WAYLAND_GENERATOR_ARGUMENT_H diff --git a/src/wayland/generator/event.cpp b/src/wayland/generator/event.cpp deleted file mode 100644 index 6e67bb02fef..00000000000 --- a/src/wayland/generator/event.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "event.h" -#include "utils.h" - -#include - -Event::Event(xmlpp::Element const& node, std::string const& class_name, int opcode) - : Method{node, class_name, true}, - opcode{opcode} -{ -} - -Emitter Event::opcode_declare() const -{ - return Line{"static uint32_t const ", sanitize_name(name), " = ", std::to_string(opcode), ";"}; -} - -// TODO: Decide whether to resolve wl_resource* to wrapped types (ie: Region, Surface, etc). -Emitter Event::prototype() const -{ - if (min_version > 0) - { - return Lines{ - {"bool version_supports_", name, "();"}, - {"void send_", name, "_event_if_supported(", mir_args(), ") const;"}, - {"void send_", name, "_event(", mir_args(), ") const;"}, - }; - } - else - { - return Lines{ - {"void send_", name, "_event(", mir_args(), ") const;"}, - }; - } -} - -// TODO: Decide whether to resolve wl_resource* to wrapped types (ie: Region, Surface, etc). -Emitter Event::impl() const -{ - Emitter const version_high_enough{"wl_resource_get_version(resource) >= ", std::to_string(min_version)}; - Lines const post_event{ - mir2wl_converters(), - {"wl_resource_post_event(", wl_call_args(), ");"}, - }; - if (min_version > 0) - { - return Lines{ - {"bool mw::", class_name, "::version_supports_", name, "()"}, - Block{ - {"return ", version_high_enough, ";"} - }, - empty_line, - {"void mw::", class_name, "::send_", name, "_event_if_supported(", mir_args(), ") const"}, - Block{ - {"if (", version_high_enough, ")"}, - Block{post_event}, - }, - empty_line, - {"void mw::", class_name, "::send_", name, "_event(", mir_args(), ") const"}, - Block{ - {"if (", version_high_enough, ")"}, - Block{post_event}, - "else", - Block{ - {"tried_to_send_unsupported_event(", - "client->raw_client(), resource, \"", name, "\", ", std::to_string(min_version), ");"}, - }, - }, - }; - } - else - { - return Lines{ - {"void mw::", class_name, "::send_", name, "_event(", mir_args(), ") const"}, - Block{post_event}, - }; - } -} - -Emitter Event::mir2wl_converters() const -{ - std::vector thunk_converters; - for (auto const& arg : arguments) - { - if (auto converter = arg.converter()) - thunk_converters.push_back(converter.value()); - } - return Lines{thunk_converters}; -} - -Emitter Event::mir_args() const -{ - std::vector mir_args; - for (auto& i : arguments) - { - mir_args.push_back(i.mir_prototype()); - } - return Emitter::seq(mir_args, ", "); -} - -Emitter Event::wl_call_args() const -{ - std::vector call_args{"resource", "Opcode::" + sanitize_name(name)}; - for (auto& arg : arguments) - call_args.push_back(arg.call_fragment()); - return Emitter::seq(call_args, ", "); -} diff --git a/src/wayland/generator/event.h b/src/wayland/generator/event.h deleted file mode 100644 index f4c9feaefd4..00000000000 --- a/src/wayland/generator/event.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_EVENT_H -#define MIR_WAYLAND_GENERATOR_EVENT_H - -#include "method.h" - -class Event : public Method -{ -public: - Event(xmlpp::Element const& node, std::string const& class_name, int opcode); - - Emitter opcode_declare() const; - Emitter prototype() const; - Emitter impl() const; - -protected: - // converts wl input types to mir types - Emitter mir2wl_converters() const; - - Emitter mir_args() const; - - // arguments to call the virtual mir function call (just names, no types) - Emitter wl_call_args() const; - - int const opcode; -}; - -#endif // MIR_WAYLAND_GENERATOR_EVENT_H diff --git a/src/wayland/generator/global.cpp b/src/wayland/generator/global.cpp deleted file mode 100644 index 04ce6c6c330..00000000000 --- a/src/wayland/generator/global.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "global.h" - -Global::Global(std::string const& wl_name, std::string const& generated_name, int version, std::string const& nmspace) - : wl_name{wl_name}, - version{version}, - generated_name{generated_name}, - nmspace{nmspace} -{ -} - -Emitter Global::declaration() const -{ - return Lines{ - {"class Global : public wayland::Global"}, - "{", - "public:", - Emitter::layout(Lines{ - {"Global(", constructor_args(), ");"}, - empty_line, - {"auto interface_name() const -> char const* override;"} - }, true, true, Emitter::single_indent), - empty_line, - "private:", - Emitter::layout(Lines{ - bind_prototype(), - {"friend ", generated_name, "::Thunks;"}, - }, true, true, Emitter::single_indent), - "};" - }; -} - -Emitter Global::implementation() const -{ - return EmptyLineList{ - Lines{ - {nmspace, "Global::Global(", constructor_args(), ")"}, - {" : wayland::Global{"}, - {" wl_global_create("}, - {" display,"}, - {" &", wl_name, "_interface_data,"}, - {" Thunks::supported_version,"}, - {" this,"}, - {" &Thunks::bind_thunk)}"}, - Block{ - } - }, - Lines{ - {"auto ", nmspace, "Global::interface_name() const -> char const*"}, - Block{ - {"return ", generated_name, "::interface_name;"}, - } - } - }; -} - -Emitter Global::bind_thunk_impl() const -{ - return Lines{ - "static void bind_thunk(struct wl_client* client, void* data, uint32_t version, uint32_t id)", - Block{ - {"auto me = static_cast<", generated_name, "::Global*>(data);"}, - {"auto resource = wl_resource_create("}, - Emitter::layout(Lines{ - "client,", - {"&", wl_name, "_interface_data,"}, - {"std::min((int)version, Thunks::supported_version),"}, - "id);", - }, true, true, Emitter::single_indent), - "if (resource == nullptr)", - Block{ - "wl_client_post_no_memory(client);", - "BOOST_THROW_EXCEPTION((std::bad_alloc{}));", - }, - "try", - Block{ - "me->bind(resource);" - }, - "catch(...)", - Block{{ - {"internal_error_processing_request(client, \"", generated_name, " global bind\");"}, - }} - } - }; -} - -Emitter Global::constructor_args() const -{ - return {"wl_display* display, Version<", std::to_string(version), ">"}; -} - -Emitter Global::bind_prototype() const -{ - return {"virtual void bind(wl_resource* new_", wl_name, ") = 0;"}; -} diff --git a/src/wayland/generator/global.h b/src/wayland/generator/global.h deleted file mode 100644 index b7700f368cc..00000000000 --- a/src/wayland/generator/global.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_GLOBAL_H -#define MIR_WAYLAND_GENERATOR_GLOBAL_H - -#include "emitter.h" - -namespace xmlpp -{ -class Element; -} - -class Global -{ -public: - Global(std::string const& wl_name, std::string const& generated_name, int version, std::string const& nmspace); - - Emitter declaration() const; - Emitter implementation() const; - Emitter bind_thunk_impl() const; - -private: - Emitter constructor_args() const; - Emitter bind_prototype() const; - - std::string const wl_name; - int const version; - std::string const generated_name; - std::string const nmspace; -}; - -#endif // MIR_WAYLAND_GENERATOR_GLOBAL_H diff --git a/src/wayland/generator/interface.cpp b/src/wayland/generator/interface.cpp deleted file mode 100644 index 02e87929ad8..00000000000 --- a/src/wayland/generator/interface.cpp +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "interface.h" - -#include - -#include "method.h" - -namespace -{ -class AsRange -{ -public: - using const_iterator = std::unordered_multimap::const_iterator; - explicit AsRange(std::pair stupid_api) - : range{std::move(stupid_api)} - { - } - - const_iterator begin() - { - return range.first; - } - - const_iterator end() - { - return range.second; - } - -private: - std::pair const range; -}; - -auto matching_keys_to_vector( - std::unordered_multimap const& map, - std::function const& name_transform, - std::string key) -{ - std::vector interfaces; - for (auto const& i : AsRange{map.equal_range(key)}) - { - interfaces.push_back(name_transform(i.second)); - } - return interfaces; -} - -auto vec_has_destroy_request(std::vector const& requests) -> bool -{ - for (auto const& request : requests) - { - if (request.is_destroy()) - { - return true; - } - } - return false; -} -} - -Interface::Interface(xmlpp::Element const& node, - std::function const& name_transform, - std::unordered_set const& constructable_interfaces, - std::unordered_multimap const& event_constructable_interfaces) - : wl_name{node.get_attribute_value("name")}, - version{std::stoi(node.get_attribute_value("version"))}, - generated_name{name_transform(wl_name)}, - nmspace{"mw::" + generated_name + "::"}, - has_server_constructor{event_constructable_interfaces.count(wl_name) != 0}, - has_client_constructor{constructable_interfaces.count(wl_name) != 0}, - global{!(has_server_constructor || has_client_constructor) ? - std::make_optional(Global{wl_name, generated_name, version, nmspace}) : - std::nullopt}, - requests{get_requests(node, generated_name)}, - events{get_events(node, generated_name)}, - enums{get_enums(node, generated_name)}, - parent_interfaces{matching_keys_to_vector(event_constructable_interfaces, name_transform, wl_name)}, - has_destroy_request{vec_has_destroy_request(requests)} -{ -} - -std::string Interface::class_name() const -{ - return generated_name; -} - -Emitter Interface::declaration() const -{ - return Lines{ - {"class ", generated_name, " : public Resource"}, - "{", - "public:", - Emitter::layout(EmptyLineList{ - {"static char const constexpr* interface_name = \"", wl_name, "\";"}, - {"static ", generated_name, "* from(struct wl_resource*);"}, - Lines { - constructor_prototypes(), - destructor_prototype(), - }, - event_prototypes(), - (has_destroy_request ? nullptr : "void destroy_and_delete() const;"), - enum_declarations(), - event_opcodes(), - (thunks_impl_contents().is_valid() ? "struct Thunks;" : nullptr), - is_instance_prototype(), - (global ? global.value().declaration() : nullptr), - }, true, true, Emitter::single_indent), - empty_line, - "private:", - Emitter::layout(EmptyLineList{ - virtual_request_prototypes(), - }, true, true, Emitter::single_indent), - "};" - }; -} - -Emitter Interface::implementation() const -{ - return Lines{ - {"// ", generated_name}, - empty_line, - EmptyLineList{ - thunks_impl(), - constructor_impl(), - destructor_impl(), - event_impls(), - is_instance_impl(), - (has_destroy_request ? Emitter{nullptr} : - Lines{ - {"void ", nmspace, "destroy_and_delete() const"}, - Block{ - {"// Will result in this object being deleted"}, - {"wl_resource_destroy(resource);"}, - } - } - ), - enum_impls(), - (global ? global.value().implementation() : nullptr), - types_init(), - Lines{ - {"mw::", generated_name, "* ", nmspace, "from(struct wl_resource* resource)"}, - Block{ - Lines{ - {"if (resource &&"}, - {" wl_resource_instance_of(resource, &", - wl_name, - "_interface_data, ", - generated_name, - "::Thunks::request_vtable))"}, - Block{ - {"return static_cast<", generated_name, "*>(wl_resource_get_user_data(resource));"} - }, - "else", - Block{ - {"return nullptr;"} - }, - }, - } - }, - }, - }; -} - -Emitter Interface::wl_interface_init() const -{ - return Lines{ - {"struct wl_interface const ", wl_name, "_interface_data ", - BraceList{ - {nmspace, "interface_name"}, - {nmspace, "Thunks::supported_version"}, - {std::to_string(requests.size()), ", ", (requests.empty() ? "nullptr" : nmspace + "Thunks::request_messages")}, - {std::to_string(events.size()), ", ", (events.empty() ? "nullptr" : nmspace + "Thunks::event_messages")} - }} - }; -} - -void Interface::populate_required_interfaces(std::set& interfaces) const -{ - interfaces.insert(wl_name); - - for (auto const& request : requests) - { - request.populate_required_interfaces(interfaces); - } - - for (auto const& event : events) - { - event.populate_required_interfaces(interfaces); - } -} - -Emitter Interface::constructor_prototypes() const -{ - std::vector prototypes; - if (has_client_constructor || global) - { - prototypes.push_back(Line{generated_name, "(", constructor_args(), ");"}); - } - if (has_server_constructor) - { - for (auto const &parent : parent_interfaces) - { - prototypes.push_back(Line{generated_name, "(", constructor_args(parent), ");"}); - } - } - return Lines{prototypes}; -} - -Emitter Interface::constructor_impl() const -{ - std::vector impls; - if (has_client_constructor || global) - { - impls.push_back(Lines{ - {nmspace, generated_name, "(", constructor_args(), ")"}, - {" : Resource{resource}"}, - Block{ - "wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);", - } - }); - } - for (auto const& parent : parent_interfaces) - { - impls.push_back(constructor_impl(parent)); - } - return Lines{impls}; -} - -Emitter Interface::constructor_impl(std::string const& parent_interface) const -{ - return Lines{ - {nmspace, generated_name, "(", constructor_args(parent_interface), ")"}, - {" : Resource{wl_resource_create("}, - {" wl_resource_get_client(parent.resource),"}, - {" &", wl_name, "_interface_data,"}, - {" wl_resource_get_version(parent.resource), 0)}"}, - Block{ - "wl_resource_set_implementation(resource, Thunks::request_vtable, this, &Thunks::resource_destroyed_thunk);", - } - }; -} - -Emitter Interface::constructor_args() const -{ - return {"struct wl_resource* resource, Version<", std::to_string(version), ">"}; -} - -Emitter Interface::constructor_args(std::string const& parent_interface) const -{ - return {parent_interface, " const& parent"}; -} - -Emitter Interface::destructor_prototype() const -{ - return Line{"virtual ~", generated_name, "();"}; -} - -Emitter Interface::destructor_impl() const -{ - return Lines{ - {nmspace, "~", generated_name, "()"}, - Block{ - "wl_resource_set_implementation(resource, nullptr, nullptr, nullptr);" - } - }; -} - -Emitter Interface::virtual_request_prototypes() const -{ - std::vector prototypes; - for (auto const& request : requests) - { - prototypes.push_back(request.virtual_mir_prototype()); - } - return Lines{prototypes}; -} - -Emitter Interface::event_prototypes() const -{ - std::vector prototypes; - for (auto const& event : events) - { - prototypes.push_back(event.prototype()); - } - return Lines{prototypes}; -} - -Emitter Interface::event_impls() const -{ - std::vector impls; - for (auto const& event : events) - { - impls.push_back(event.impl()); - } - return EmptyLineList{impls}; -} - -Emitter Interface::is_instance_prototype() const -{ - return "static bool is_instance(wl_resource* resource);"; -} - -Emitter Interface::is_instance_impl() const -{ - return Lines{ - {"bool ", nmspace, "is_instance(wl_resource* resource)"}, - Block{"return wl_resource_instance_of(resource, &" + wl_name + "_interface_data, Thunks::request_vtable);"} - }; -} - -Emitter Interface::enum_declarations() const -{ - std::vector declarations; - for (auto const& i : enums) - { - declarations.push_back(i.declaration()); - } - return EmptyLineList{declarations}; -} - -Emitter Interface::enum_impls() const -{ - std::vector declarations; - for (auto const& i : enums) - { - declarations.push_back(i.impl()); - } - return Lines{declarations}; -} - -Emitter Interface::event_opcodes() const -{ - std::vector opcodes; - for (auto const& i : events) - { - opcodes.push_back(i.opcode_declare()); - } - Emitter body{opcodes}; - if (body.is_valid()) - { - return Lines{ - {"struct Opcode"}, - {Block{ - body - }, ";"} - }; - } - else - { - return nullptr; - } -} - -Emitter Interface::thunks_impl() const -{ - Emitter contents = thunks_impl_contents(); - - if (contents.is_valid()) - { - return Lines{ - {"struct ", nmspace, "Thunks"}, - {Block{ - contents - }, ";"}, - empty_line, - {"int const ", nmspace, "Thunks::supported_version = ", std::to_string(version), ";"}, - }; - } - else - { - return nullptr; - } -} - -Emitter Interface::thunks_impl_contents() const -{ - std::vector impls; - impls.push_back( - {"static int const supported_version;"}); - - for (auto const& request : requests) - impls.push_back(request.thunk_impl()); - - impls.push_back(resource_destroyed_thunk()); - - if (global) - impls.push_back(global.value().bind_thunk_impl()); - - std::vector declares; - for (auto const& request : requests) - declares.push_back(request.types_declare()); - for (auto const& event : events) - declares.push_back(event.types_declare()); - if (!requests.empty()) - declares.push_back("static struct wl_message const request_messages[];"); - if (!events.empty()) - declares.push_back("static struct wl_message const event_messages[];"); - declares.push_back({"static void const* request_vtable[];"}); - impls.push_back(Lines{declares}); - - return EmptyLineList{impls}; -} - -Emitter Interface::resource_destroyed_thunk() const -{ - return Lines{ - "static void resource_destroyed_thunk(wl_resource* resource)", - Block{ - {"delete static_cast<", generated_name, "*>(wl_resource_get_user_data(resource));"} - } - }; -} - -Emitter Interface::types_init() const -{ - std::vector types; - for (auto const& request : requests) - types.push_back(request.types_init()); - for (auto const& event : events) - types.push_back(event.types_init()); - - if (!requests.empty()) - { - std::vector request_messages; - for (auto const& request : requests) - request_messages.push_back(request.wl_message_init()); - - types.push_back(Lines{ - {"struct wl_message const ", nmspace, "Thunks::request_messages[] ", - BraceList{request_messages}} - }); - } - - if (!events.empty()) - { - std::vector event_messages; - for (auto const& event : events) - event_messages.push_back(event.wl_message_init()); - - types.push_back(Lines{ - {"struct wl_message const ", nmspace, "Thunks::event_messages[] ", - BraceList{event_messages}} - }); - } - - std::vector request_initializers; - for (auto const& request : requests) - { - request_initializers.push_back({"(void*)Thunks::", request.vtable_initialiser()}); - } - - if (request_initializers.empty()) - { - request_initializers.push_back("nullptr"); - } - - types.push_back(Lines{ - {"void const* ", nmspace, "Thunks::request_vtable[] ", - BraceList{request_initializers}}, - }); - - return EmptyLineList{types}; -} - -std::vector Interface::get_requests(xmlpp::Element const& node, std::string generated_name) -{ - std::vector requests; - for (auto method_node : node.get_children("request")) - { - auto elem = dynamic_cast(method_node); - requests.emplace_back(Request{std::ref(*elem), generated_name}); - } - return requests; -} - -std::vector Interface::get_events(xmlpp::Element const& node, std::string generated_name) -{ - std::vector events; - int opcode = 0; - for (auto method_node : node.get_children("event")) - { - auto elem = dynamic_cast(method_node); - events.emplace_back(Event{std::ref(*elem), generated_name, opcode}); - opcode++; - } - return events; -} - -std::vector Interface::get_enums(xmlpp::Element const& node, std::string generated_name) -{ - std::vector enums; - for (auto method_node : node.get_children("enum")) - { - auto elem = dynamic_cast(method_node); - enums.emplace_back(Enum{std::ref(*elem), generated_name}); - } - return enums; -} diff --git a/src/wayland/generator/interface.h b/src/wayland/generator/interface.h deleted file mode 100644 index c0ad8b2610b..00000000000 --- a/src/wayland/generator/interface.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_INTERFACE_H -#define MIR_WAYLAND_GENERATOR_INTERFACE_H - -#include "emitter.h" -#include "request.h" -#include "event.h" -#include "enum.h" -#include "global.h" - -#include -#include -#include -#include - -class Method; - -namespace xmlpp -{ -class Element; -} - -class Interface -{ -public: - Interface(xmlpp::Element const& node, - std::function const& name_transform, - std::unordered_set const& constructible_interfaces, - std::unordered_multimap const& event_constructable_interfaces); - - std::string class_name() const; - Emitter declaration() const; - Emitter implementation() const; - Emitter wl_interface_init() const; - void populate_required_interfaces(std::set& interfaces) const; // fills the set with interfaces used - -private: - Emitter constructor_prototypes() const; - Emitter constructor_impl() const; - Emitter constructor_impl(std::string const& parent_interface) const; - Emitter constructor_args() const; - Emitter constructor_args(std::string const& parent_interface) const; - Emitter destructor_prototype() const; - Emitter destructor_impl() const; - Emitter virtual_request_prototypes() const; - Emitter event_prototypes() const; - Emitter event_impls() const; - Emitter enum_declarations() const; - Emitter enum_impls() const; - Emitter event_opcodes() const; - Emitter thunks_impl() const; - Emitter thunks_impl_contents() const; - Emitter resource_destroyed_thunk() const; - Emitter types_init() const; - Emitter is_instance_prototype() const; - Emitter is_instance_impl() const; - - static std::vector get_requests(xmlpp::Element const& node, std::string generated_name); - static std::vector get_events(xmlpp::Element const& node, std::string generated_name); - static std::vector get_enums(xmlpp::Element const& node, std::string generated_name); - - std::string const wl_name; - int const version; - std::string const generated_name; - std::string const nmspace; - bool const has_server_constructor; - bool const has_client_constructor; - std::optional const global; - std::vector const requests; - std::vector const events; - std::vector const enums; - std::vector const parent_interfaces; - bool const has_destroy_request; -}; - -#endif // MIR_WAYLAND_GENERATOR_INTERFACE_H diff --git a/src/wayland/generator/method.cpp b/src/wayland/generator/method.cpp deleted file mode 100644 index 98d206007c5..00000000000 --- a/src/wayland/generator/method.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "method.h" -#include "utils.h" - -#include - -Method::Method(xmlpp::Element const& node, std::string const& class_name, bool is_event) - : name{node.get_attribute_value("name")}, - type{node.get_attribute_value("type")}, - class_name{class_name}, - min_version{get_since_version(node)} -{ - for (auto const& child : node.get_children("arg")) - { - auto arg_node = dynamic_cast(child); - arguments.emplace_back(std::ref(*arg_node), is_event); - } -} - -Emitter Method::types_str() const -{ - std::vector contents; - - if (min_version > 0) - contents.push_back(std::to_string(min_version)); - - for (auto const& arg : arguments) - contents.push_back(arg.type_str_fragment()); - - return {"\"", Emitter{contents}, "\""}; -} - -Emitter Method::types_declare() const -{ - if (use_null_types()) - return nullptr; - - std::vector types; - - for (auto const& arg : arguments) - { - Emitter e = arg.object_type_fragment(); - if (e.is_valid()) - types.push_back(e); - else - types.push_back("nullptr"); - } - - return {"static struct wl_interface const* ", name, "_types[];"}; -} - -Emitter Method::types_init() const -{ - if (use_null_types()) - return nullptr; - - std::vector types_vec, declares_vec; - - for (auto const& arg : arguments) - { - Emitter e = arg.object_type_fragment(); - if (e.is_valid()) - types_vec.push_back(e); - else - types_vec.push_back("nullptr"); - } - - Emitter declares = Lines{declares_vec}; - - if (declares.is_valid()) - { - declares = Lines{ - "// forward declarations of needed types", - declares, - empty_line - }; - } - - return Lines{ - declares, - {"struct wl_interface const* mw::", class_name, "::Thunks::", name, "_types[] ", - BraceList{types_vec}} - }; -} - -Emitter Method::wl_message_init() const -{ - return {"{\"", name, "\", ", types_str(), ", ", (use_null_types() ? "all_null_types" : name + "_types"), "}"}; -} - -void Method::populate_required_interfaces(std::set& interfaces) const -{ - for (auto const& arg : arguments) - { - arg.populate_required_interfaces(interfaces); - } -} - -int Method::get_since_version(xmlpp::Element const& node) -{ - try - { - return std::stoi(node.get_attribute_value("since")); - } - catch (std::invalid_argument const&) - { - return 0; - } -} - -bool Method::use_null_types() const -{ - if (arguments.size() > all_null_types_size) - return false; - - for (auto const& i : arguments) - { - if (i.object_type_fragment().is_valid()) - return false; - } - - return true; -} diff --git a/src/wayland/generator/method.h b/src/wayland/generator/method.h deleted file mode 100644 index c54b092c926..00000000000 --- a/src/wayland/generator/method.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_METHOD_H -#define MIR_WAYLAND_GENERATOR_METHOD_H - -#include "emitter.h" -#include "argument.h" - -#include -#include -#include - -namespace xmlpp -{ -class Element; -} - -class Method -{ -public: - Method(xmlpp::Element const& node, std::string const& class_name, bool is_event); - - Emitter types_str() const; - Emitter types_declare() const; - Emitter types_init() const; - Emitter wl_message_init() const; - - void populate_required_interfaces(std::set& interfaces) const; // fills the set with interfaces used - -protected: - - bool use_null_types() const; - - static int get_since_version(xmlpp::Element const& node); - - std::string const name; - std::string const type; - std::string const class_name; - int const min_version; - std::vector arguments; -}; - -#endif // MIR_WAYLAND_GENERATOR_METHOD_H diff --git a/src/wayland/generator/request.cpp b/src/wayland/generator/request.cpp deleted file mode 100644 index 66b46bed2cb..00000000000 --- a/src/wayland/generator/request.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "request.h" - -Request::Request(xmlpp::Element const& node, std::string const& class_name) - : Method{node, class_name, false} -{ -} - -// TODO: Decide whether to resolve wl_resource* to wrapped types (ie: Region, Surface, etc). -Emitter Request::virtual_mir_prototype() const -{ - if (is_destroy()) - { - return {"virtual void ", name, "(", mir_args(), ") {}"}; - } - else - { - return {"virtual void ", name, "(", mir_args(), ") = 0;"}; - } -} - -// TODO: Decide whether to resolve wl_resource* to wrapped types (ie: Region, Surface, etc). -Emitter Request::thunk_impl() const -{ - return {"static void ", name, "_thunk(", wl_args(), ")", - Block{ - wl2mir_converters(), - "try", - Block{ - (is_destroy() ? - Lines{ - {"auto me = static_cast<", class_name, "*>(wl_resource_get_user_data(resource));"}, - {"me->", name, "(", mir_call_args(), ");"}, - {"wl_resource_destroy(resource);"} - } - : - Lines{ - {"auto me = static_cast<", class_name, "*>(wl_resource_get_user_data(resource));"}, - {"me->", name, "(", mir_call_args(), ");"}, - } - ) - }, - "catch(ProtocolError const& err)", - Block{ - {"wl_resource_post_error(err.resource(), err.code(), \"%s\", err.message());"}, - }, - "catch(...)", - Block{ - {"internal_error_processing_request(client, \"", class_name, "::", name, "()\");"}, - } - } - }; -} - -Emitter Request::vtable_initialiser() const -{ - return {name, "_thunk"}; -} - -bool Request::is_destroy() const -{ - return type == "destructor"; -} - -Emitter Request::wl_args() const -{ - Emitter client_arg = "struct wl_client* client"; - std::vector wl_args{client_arg, "struct wl_resource* resource"}; - for (auto const& arg : arguments) - wl_args.push_back(arg.wl_prototype()); - return Emitter::seq(wl_args, ", "); -} - -Emitter Request::mir_args() const -{ - std::vector mir_args; - for (auto& i : arguments) - { - mir_args.push_back(i.mir_prototype()); - } - return Emitter::seq(mir_args, ", "); -} - -Emitter Request::wl2mir_converters() const -{ - std::vector thunk_converters; - for (auto const& arg : arguments) - { - if (auto converter = arg.converter()) - thunk_converters.push_back(converter.value()); - } - return Lines{thunk_converters}; -} - -Emitter Request::mir_call_args() const -{ - std::vector call_args; - for (auto& arg : arguments) - call_args.push_back(arg.call_fragment()); - return Emitter::seq(call_args, ", "); -} diff --git a/src/wayland/generator/request.h b/src/wayland/generator/request.h deleted file mode 100644 index e82224d76ef..00000000000 --- a/src/wayland/generator/request.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_REQUEST_H -#define MIR_WAYLAND_GENERATOR_REQUEST_H - -#include "method.h" - -class Request : public Method -{ -public: - Request(xmlpp::Element const& node, std::string const& class_name); - - // prototype of virtual function that is overridden in Mir - Emitter virtual_mir_prototype() const; - - // the thunk is the static function that libwayland calls - // It does some type conversion and calls the virtual method, which should be overridden somewhere in Mir - Emitter thunk_impl() const; - - // the bit of this object's vtable that holds this method - Emitter vtable_initialiser() const; - - // If this request destroys the object - bool is_destroy() const; - -protected: - // arguments from libwayland to the thunk - Emitter wl_args() const; - - // arguments for mir code - Emitter mir_args() const; - - // converts wl input types to mir types - Emitter wl2mir_converters() const; - - // arguments to call the virtual mir function call (just names, no types) - Emitter mir_call_args() const; -}; - -#endif // MIR_WAYLAND_GENERATOR_REQUEST_H diff --git a/src/wayland/generator/utils.cpp b/src/wayland/generator/utils.cpp deleted file mode 100644 index 989422e71e2..00000000000 --- a/src/wayland/generator/utils.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "utils.h" - -#include -#include -#include - -const std::vector cpp_reserved_keywords = { - "namespace", - "class", - "auto", - "default"}; // add to this on an as-needed basis - -std::string file_name_from_path(std::string const& path) -{ - size_t i = path.find_last_of("/"); - if (i == std::string::npos) - return path; - else - return path.substr(i + 1); -} - -std::string sanitize_name(std::string const& name_, bool escape_invalid) -{ - std::string name = name_; - if (name.empty()) - name = "__EMPTY_NAME"; - if (name[0] >= '0' && name[0] <= '9') - name = "_" + name; - for (unsigned long i = 0; i < name.size(); i++) - { - char c = name[i]; - if ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - (c == '_')) - { - // all good - } - else - { - std::string replace_str = "_"; - if (escape_invalid) - replace_str = "_ASC" + std::to_string((int)name[i]) + "_"; - name.replace(i, 1, replace_str); - } - } - for (auto const& i: cpp_reserved_keywords) - { - if (i == name) - { - name = name + "_"; - } - } - return name; -} - -std::string to_upper_case(std::string const& name) -{ - std::string macro_name = ""; - for (unsigned i = 0; i < name.size(); i++) - { - macro_name += std::toupper(name[i], std::locale("C")); - } - return sanitize_name(macro_name, false); -} - -std::string to_camel_case(std::string const& name) -{ - std::string camel_cased_name; - camel_cased_name = std::string{std::toupper(name[0], std::locale("C"))} + name.substr(1); - auto next_underscore_offset = name.find('_'); - while (next_underscore_offset != std::string::npos) - { - if (next_underscore_offset < camel_cased_name.length()) - { - camel_cased_name = camel_cased_name.substr(0, next_underscore_offset) + - std::toupper(camel_cased_name[next_underscore_offset + 1], std::locale("C")) + - camel_cased_name.substr(next_underscore_offset + 2); - } - next_underscore_offset = camel_cased_name.find('_', next_underscore_offset); - } - return sanitize_name(camel_cased_name); -} diff --git a/src/wayland/generator/utils.h b/src/wayland/generator/utils.h deleted file mode 100644 index 144d4446015..00000000000 --- a/src/wayland/generator/utils.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MIR_WAYLAND_GENERATOR_WRAPPER_GENERATOR_H -#define MIR_WAYLAND_GENERATOR_WRAPPER_GENERATOR_H - -#include - -int const all_null_types_size = 6; - -// remove the path from a file path, leaving only the base name -std::string file_name_from_path(std::string const& path); - -// make sure the name is not a C++ reserved word, could be expanded to get rid of invalid characters if that was needed -std::string sanitize_name(std::string const& name, bool escape_invalid = true); - -// converts any string into a valid, all upper case macro name (replacing special chars with underscores) -std::string to_upper_case(std::string const& name); - -// converts a snake_case string into a CamelCase string, for type names -std::string to_camel_case(std::string const& name); - -#endif // MIR_WAYLAND_GENERATOR_WRAPPER_GENERATOR_H diff --git a/src/wayland/generator/wrapper_generator.cpp b/src/wayland/generator/wrapper_generator.cpp deleted file mode 100644 index 102af236b77..00000000000 --- a/src/wayland/generator/wrapper_generator.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "emitter.h" -#include "interface.h" -#include "utils.h" - -#include -#include - -Emitter comment_header(std::string const& input_file_path) -{ - return Lines{ - "/*", - " * AUTOGENERATED - DO NOT EDIT", - " *", - {" * This file is generated from ", file_name_from_path(input_file_path), " by mir_wayland_generator"}, - " */", - }; -} - -Emitter include_guard_top(std::string const& macro) -{ - return Lines{ - {"#ifndef ", macro}, - {"#define ", macro}, - }; -} - -Emitter header_includes() -{ - return Lines{ - "#include ", - empty_line, - "#include ", - "#include ", - empty_line, - "#include ", - "#include ", - }; -} - -Emitter impl_includes(std::string const& protocol_name) -{ - return Lines{ - {"#include \"", protocol_name, "_wrapper.h\""}, - empty_line, - "#include ", - "#include ", - empty_line, - "#include ", - "#include ", - }; -} - -Emitter include_guard_bottom(std::string const& macro) -{ - return Lines{ - {"#endif // ", macro} - }; -} - -Emitter forward_declarations_for(std::vector const& interfaces) -{ - std::vector decls; - for (auto const& interface : interfaces) - { - decls.push_back(Line{"class ", interface.class_name(), ";"}); - } - return Lines{decls}; -} - -Emitter header_file(std::string input_file_path, std::vector const& interfaces) -{ - std::string const include_guard_macro = to_upper_case("MIR_FRONTEND_WAYLAND_" + file_name_from_path(input_file_path) + "_WRAPPER"); - - std::vector interface_emitters; - for (auto const& interface : interfaces) - { - interface_emitters.push_back(interface.declaration()); - } - - return Lines{ - comment_header(input_file_path), - empty_line, - include_guard_top(include_guard_macro), - empty_line, - header_includes(), - empty_line, - "namespace mir", - "{", - "namespace wayland", - "{", - empty_line, - forward_declarations_for(interfaces), - empty_line, - EmptyLineList{interface_emitters}, - empty_line, - "}", - "}", - empty_line, - include_guard_bottom(include_guard_macro) - }; -} - -Emitter source_file(std::string input_file_path, std::vector const& interfaces) -{ - std::vector interface_emitters, wl_interface_init_emitters; - std::set fwd_declare_interfaces; - for (auto const& interface : interfaces) - { - interface_emitters.push_back(interface.implementation()); - wl_interface_init_emitters.push_back(interface.wl_interface_init()); - interface.populate_required_interfaces(fwd_declare_interfaces); - } - - std::vector fwd_declare_interface_emitters; - for (auto const& interface_name : fwd_declare_interfaces) - { - fwd_declare_interface_emitters.push_back({"extern struct wl_interface const ", interface_name, "_interface_data;"}); - } - - std::string protocol_name = file_name_from_path(input_file_path); - if (protocol_name.substr(protocol_name.size() - 4) == ".xml") - protocol_name = protocol_name.substr(0, protocol_name.size() - 4); - - return Lines{ - comment_header(input_file_path), - empty_line, - impl_includes(protocol_name), - empty_line, - "namespace mir", - "{", - "namespace wayland", - "{", - Lines{fwd_declare_interface_emitters}, - "}", - "}", - empty_line, - "namespace mw = mir::wayland;", - empty_line, - "namespace", - "{", - {"struct wl_interface const* all_null_types [] ", - BraceList{std::vector(all_null_types_size, "nullptr")}}, - "}", - empty_line, - EmptyLineList{interface_emitters}, - empty_line, - "namespace mir", - "{", - "namespace wayland", - "{", - empty_line, - EmptyLineList{wl_interface_init_emitters}, - empty_line, - "}", - "}", - }; -} - -int main(int argc, char** argv) -{ - Emitter usage_emitter = Lines{ - empty_line, - "/*", - {"Usage: ./", file_name_from_path(argv[0]), " "}, - Block{ - "prefix: the name prefix which will be removed, such as wl_", - " to not use a prefix, use _ or anything that won't match the start of a name", - "input: the input xml file path", - "mode: 'header' or 'source'", - }, - "*/", - empty_line, - }; - - if (argc != 4) - { - usage_emitter.emit({std::cerr}); - usage_emitter.emit({std::cout}); - exit(1); - } - - std::string const prefix{argv[1]}; - std::string const input_file_path{argv[2]}; - bool header_mode{true}; - std::string mode_str = argv[3]; - if (mode_str == "header") - { - header_mode = true; - } - else if (mode_str == "source") - { - header_mode = false; - } - else - { - usage_emitter.emit({std::cerr}); - usage_emitter.emit({std::cout}); - exit(1); - } - - auto name_transform = [prefix](std::string protocol_name) - { - std::string transformed_name = protocol_name; - if (protocol_name.find(prefix) == 0) // if the first instance of prefix is at the start of protocol_name - { - // cut off the prefix - transformed_name = protocol_name.substr(prefix.length()); - } - return to_camel_case(transformed_name); - }; - - xmlpp::DomParser parser(input_file_path); - - auto document = parser.get_document(); - - auto root_node = document->get_root_node(); - - auto constructor_nodes = root_node->find("//arg[@type='new_id']"); - std::unordered_set client_constructable_interfaces; - std::unordered_multimap server_constructable_interfaces; - for (auto const node : constructor_nodes) - { - auto arg = dynamic_cast(node); - - auto const constructor_request = arg->get_parent(); - auto const interface_name = arg->get_attribute_value("interface"); - if (constructor_request->get_name() == "event") - { - // A new_id in an event means the server has constructed the object, - // and hence will choose the ID. - auto const parent_interface = constructor_request->get_parent(); - auto const parent_name = parent_interface->get_attribute_value("name"); - server_constructable_interfaces.insert({interface_name, parent_name}); - } - else if (constructor_request->get_name() == "request") - { - // new_id in a request is a client-initiated construction; - // the client has already selected the ID - client_constructable_interfaces.insert(interface_name); - } - } - - std::vector interfaces; - for (auto top_level : root_node->get_children("interface")) - { - auto interface = dynamic_cast(top_level); - - if (interface->get_attribute_value("name") == "wl_display" || - interface->get_attribute_value("name") == "wl_registry") - { - // These are special, and don't need binding. - continue; - } - interfaces.emplace_back( - *interface, - name_transform, - client_constructable_interfaces, - server_constructable_interfaces); - } - - Emitter emitter{nullptr}; - if (header_mode) - emitter = header_file(input_file_path, interfaces); - else - emitter = source_file(input_file_path, interfaces); - - emitter.emit({std::cout}); -} diff --git a/src/wayland/global.cpp b/src/wayland/global.cpp deleted file mode 100644 index e02bed63e4e..00000000000 --- a/src/wayland/global.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include -#include - -namespace mw = mir::wayland; - -mw::Global::Global(wl_global* global) - : global{global} -{ - if (global == nullptr) - { - BOOST_THROW_EXCEPTION((std::bad_alloc{})); - } -} - -mw::Global::~Global() -{ - wl_global_destroy(global); -} diff --git a/src/wayland/lifetime_tracker.cpp b/src/wayland/lifetime_tracker.cpp deleted file mode 100644 index a0ab7f5b34f..00000000000 --- a/src/wayland/lifetime_tracker.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include - -namespace mw = mir::wayland; - -struct mw::LifetimeTracker::Impl -{ - std::shared_ptr destroyed{nullptr}; - std::map> destroy_listeners; - DestroyListenerId last_id{0}; -}; - -mw::LifetimeTracker::LifetimeTracker() -{ -} - -mw::LifetimeTracker::~LifetimeTracker() -{ - mark_destroyed(); -} - -auto mw::LifetimeTracker::destroyed_flag() const -> std::shared_ptr -{ - if (!impl) - { - impl = std::make_unique(); - } - if (!impl->destroyed) - { - impl->destroyed = std::make_shared(false); - } - return impl->destroyed; -} - -auto mw::LifetimeTracker::add_destroy_listener(std::function listener) const -> DestroyListenerId -{ - if (!impl) - { - impl = std::make_unique(); - } - auto const id = DestroyListenerId{impl->last_id.as_value() + 1}; - impl->last_id = id; - impl->destroy_listeners[id] = listener; - return id; -} - -void mw::LifetimeTracker::remove_destroy_listener(DestroyListenerId id) const -{ - if (impl) - { - impl->destroy_listeners.erase(id); - } -} - -void mw::LifetimeTracker::mark_destroyed() const -{ - if (impl) - { - auto const local_listeners = std::move(impl->destroy_listeners); - impl->destroy_listeners.clear(); - for (auto const& listener : local_listeners) - { - listener.second(); - } - if (impl->destroyed) - { - *impl->destroyed = true; - } - } -} diff --git a/src/wayland/mirwayland.pc.in b/src/wayland/mirwayland.pc.in deleted file mode 100644 index 8faf51fdf4c..00000000000 --- a/src/wayland/mirwayland.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@PKGCONFIG_LIBDIR@ -includedir=@PKGCONFIG_INCLUDEDIR@/mirwayland - -Name: mirwayland -Description: Mir Wayland library -Version: @PROJECT_VERSION@ -Requires: mircore wayland-server -Libs: -L${libdir} -lmirwayland -Cflags: -I${includedir} diff --git a/src/wayland/protocol_error.cpp b/src/wayland/protocol_error.cpp deleted file mode 100644 index ad9349759a8..00000000000 --- a/src/wayland/protocol_error.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include - -namespace mw = mir::wayland; - -mw::ProtocolError::ProtocolError( - wl_resource* source, - uint32_t code, - char const* fmt, ...) : - std::runtime_error{"Client protocol error"}, - source{source}, - error_code{code} -{ - va_list va; - char message[1024]; - - va_start(va, fmt); - auto const max = sizeof(message) - 1; - auto const len = vsnprintf(message, max, fmt, va); - va_end(va); - - error_message = std::string(std::begin(message), std::begin(message) + len); -} - -auto mw::ProtocolError::message() const -> char const* -{ - return error_message.c_str(); -} - -auto mw::ProtocolError::resource() const -> wl_resource* -{ - return source; -} - -auto mw::ProtocolError::code() const -> uint32_t -{ - return error_code; -} - -void mw::internal_error_processing_request(wl_client* client, char const* method_name) -{ - wl_client_post_implementation_error(client, "Mir internal error processing %s request", method_name); - - ::mir::log( - ::mir::logging::Severity::warning, - "frontend:Wayland", - std::current_exception(), - std::string() + "Exception processing " + method_name + " request"); -} - -void mw::tried_to_send_unsupported_event(wl_client* client, wl_resource* resource, char const* event, int required_version) -{ - wl_client_post_implementation_error( - client, - "Mir tried to send %s@%u.%s to object with version %d (requires version %d)", - wl_resource_get_class(resource), - wl_resource_get_id(resource), - event, - wl_resource_get_version(resource), - required_version); - - log_critical( - "Tried to send %s@%u.%s to object with version %d (requires version %d)", - wl_resource_get_class(resource), - wl_resource_get_id(resource), - event, - wl_resource_get_version(resource), - required_version); -} diff --git a/src/wayland/resource.cpp b/src/wayland/resource.cpp deleted file mode 100644 index 81fca830860..00000000000 --- a/src/wayland/resource.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright © Canonical Ltd. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 or 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -#include -#include - -namespace mw = mir::wayland; - -mw::Resource::Resource(wl_resource* resource) - : owned_client{Client::shared_from(wl_resource_get_client(resource))}, - resource{resource}, - client{owned_client.get()} -{ - if (resource == nullptr) - { - BOOST_THROW_EXCEPTION((std::bad_alloc{})); - } -} - -mw::Resource::~Resource() -{ - // Run destroy listeners before client is dropped - mark_destroyed(); -} diff --git a/src/wayland/symbols.map b/src/wayland/symbols.map deleted file mode 100644 index bcbdc6e2748..00000000000 --- a/src/wayland/symbols.map +++ /dev/null @@ -1,654 +0,0 @@ -MIRWAYLAND_2.17 { -global: - extern "C++" { - mir::wayland::Buffer::*; - non-virtual?thunk?to?mir::wayland::Buffer::*; - virtual?thunk?to?mir::wayland::Buffer::*; - typeinfo?for?mir::wayland::Buffer; - vtable?for?mir::wayland::Buffer; - typeinfo?for?mir::wayland::Buffer::Global; - vtable?for?mir::wayland::Buffer::Global; - - mir::wayland::Callback::*; - non-virtual?thunk?to?mir::wayland::Callback::*; - typeinfo?for?mir::wayland::Callback; - vtable?for?mir::wayland::Callback; - typeinfo?for?mir::wayland::Callback::Global; - vtable?for?mir::wayland::Callback::Global; - - mir::wayland::Compositor::*; - non-virtual?thunk?to?mir::wayland::Compositor::*; - typeinfo?for?mir::wayland::Compositor; - vtable?for?mir::wayland::Compositor; - typeinfo?for?mir::wayland::Compositor::Global; - vtable?for?mir::wayland::Compositor::Global; - - mir::wayland::DataDevice::*; - non-virtual?thunk?to?mir::wayland::DataDevice::*; - typeinfo?for?mir::wayland::DataDevice; - vtable?for?mir::wayland::DataDevice; - typeinfo?for?mir::wayland::DataDevice::Global; - vtable?for?mir::wayland::DataDevice::Global; - - mir::wayland::DataDeviceManager::*; - non-virtual?thunk?to?mir::wayland::DataDeviceManager::*; - typeinfo?for?mir::wayland::DataDeviceManager; - vtable?for?mir::wayland::DataDeviceManager; - typeinfo?for?mir::wayland::DataDeviceManager::Global; - vtable?for?mir::wayland::DataDeviceManager::Global; - - mir::wayland::DataOffer::*; - non-virtual?thunk?to?mir::wayland::DataOffer::*; - typeinfo?for?mir::wayland::DataOffer; - vtable?for?mir::wayland::DataOffer; - typeinfo?for?mir::wayland::DataOffer::Global; - vtable?for?mir::wayland::DataOffer::Global; - - mir::wayland::DataSource::*; - non-virtual?thunk?to?mir::wayland::DataSource::*; - typeinfo?for?mir::wayland::DataSource; - vtable?for?mir::wayland::DataSource; - typeinfo?for?mir::wayland::DataSource::Global; - vtable?for?mir::wayland::DataSource::Global; - - mir::wayland::Keyboard::*; - non-virtual?thunk?to?mir::wayland::Keyboard::*; - typeinfo?for?mir::wayland::Keyboard; - vtable?for?mir::wayland::Keyboard; - typeinfo?for?mir::wayland::Keyboard::Global; - vtable?for?mir::wayland::Keyboard::Global; - - mir::wayland::LayerShellV1::*; - non-virtual?thunk?to?mir::wayland::LayerShellV1::*; - typeinfo?for?mir::wayland::LayerShellV1; - vtable?for?mir::wayland::LayerShellV1; - typeinfo?for?mir::wayland::LayerShellV1::Global; - vtable?for?mir::wayland::LayerShellV1::Global; - - mir::wayland::LayerSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::LayerSurfaceV1::*; - typeinfo?for?mir::wayland::LayerSurfaceV1; - vtable?for?mir::wayland::LayerSurfaceV1; - typeinfo?for?mir::wayland::LayerSurfaceV1::Global; - vtable?for?mir::wayland::LayerSurfaceV1::Global; - - mir::wayland::Output::*; - non-virtual?thunk?to?mir::wayland::Output::*; - typeinfo?for?mir::wayland::Output; - vtable?for?mir::wayland::Output; - typeinfo?for?mir::wayland::Output::Global; - vtable?for?mir::wayland::Output::Global; - - mir::wayland::Pointer::*; - non-virtual?thunk?to?mir::wayland::Pointer::*; - typeinfo?for?mir::wayland::Pointer; - vtable?for?mir::wayland::Pointer; - typeinfo?for?mir::wayland::Pointer::Global; - vtable?for?mir::wayland::Pointer::Global; - - mir::wayland::Region::*; - non-virtual?thunk?to?mir::wayland::Region::*; - typeinfo?for?mir::wayland::Region; - vtable?for?mir::wayland::Region; - typeinfo?for?mir::wayland::Region::Global; - vtable?for?mir::wayland::Region::Global; - - mir::wayland::Seat::*; - non-virtual?thunk?to?mir::wayland::Seat::*; - typeinfo?for?mir::wayland::Seat; - vtable?for?mir::wayland::Seat; - typeinfo?for?mir::wayland::Seat::Global; - vtable?for?mir::wayland::Seat::Global; - - mir::wayland::Shell::*; - non-virtual?thunk?to?mir::wayland::Shell::*; - typeinfo?for?mir::wayland::Shell; - vtable?for?mir::wayland::Shell; - typeinfo?for?mir::wayland::Shell::Global; - vtable?for?mir::wayland::Shell::Global; - - mir::wayland::ShellSurface::*; - non-virtual?thunk?to?mir::wayland::ShellSurface::*; - typeinfo?for?mir::wayland::ShellSurface; - vtable?for?mir::wayland::ShellSurface; - typeinfo?for?mir::wayland::ShellSurface::Global; - vtable?for?mir::wayland::ShellSurface::Global; - - mir::wayland::Shm::*; - non-virtual?thunk?to?mir::wayland::Shm::*; - typeinfo?for?mir::wayland::Shm; - vtable?for?mir::wayland::Shm; - typeinfo?for?mir::wayland::Shm::Global; - vtable?for?mir::wayland::Shm::Global; - - mir::wayland::ShmPool::*; - non-virtual?thunk?to?mir::wayland::ShmPool::*; - typeinfo?for?mir::wayland::ShmPool; - vtable?for?mir::wayland::ShmPool; - typeinfo?for?mir::wayland::ShmPool::Global; - vtable?for?mir::wayland::ShmPool::Global; - - mir::wayland::Subcompositor::*; - non-virtual?thunk?to?mir::wayland::Subcompositor::*; - typeinfo?for?mir::wayland::Subcompositor; - vtable?for?mir::wayland::Subcompositor; - typeinfo?for?mir::wayland::Subcompositor::Global; - vtable?for?mir::wayland::Subcompositor::Global; - - mir::wayland::Subsurface::*; - non-virtual?thunk?to?mir::wayland::Subsurface::*; - typeinfo?for?mir::wayland::Subsurface; - vtable?for?mir::wayland::Subsurface; - typeinfo?for?mir::wayland::Subsurface::Global; - vtable?for?mir::wayland::Subsurface::Global; - - mir::wayland::Surface::*; - non-virtual?thunk?to?mir::wayland::Surface::*; - typeinfo?for?mir::wayland::Surface; - vtable?for?mir::wayland::Surface; - typeinfo?for?mir::wayland::Surface::Global; - vtable?for?mir::wayland::Surface::Global; - - mir::wayland::Touch::*; - non-virtual?thunk?to?mir::wayland::Touch::*; - typeinfo?for?mir::wayland::Touch; - vtable?for?mir::wayland::Touch; - typeinfo?for?mir::wayland::Touch::Global; - vtable?for?mir::wayland::Touch::Global; - - mir::wayland::XdgPopup::*; - non-virtual?thunk?to?mir::wayland::XdgPopup::*; - typeinfo?for?mir::wayland::XdgPopup; - vtable?for?mir::wayland::XdgPopup; - typeinfo?for?mir::wayland::XdgPopup::Global; - vtable?for?mir::wayland::XdgPopup::Global; - - mir::wayland::XdgPopupV6::*; - non-virtual?thunk?to?mir::wayland::XdgPopupV6::*; - typeinfo?for?mir::wayland::XdgPopupV6; - vtable?for?mir::wayland::XdgPopupV6; - typeinfo?for?mir::wayland::XdgPopupV6::Global; - vtable?for?mir::wayland::XdgPopupV6::Global; - - mir::wayland::XdgPositioner::*; - non-virtual?thunk?to?mir::wayland::XdgPositioner::*; - typeinfo?for?mir::wayland::XdgPositioner; - vtable?for?mir::wayland::XdgPositioner; - typeinfo?for?mir::wayland::XdgPositioner::Global; - vtable?for?mir::wayland::XdgPositioner::Global; - - mir::wayland::XdgPositionerV6::*; - non-virtual?thunk?to?mir::wayland::XdgPositionerV6::*; - typeinfo?for?mir::wayland::XdgPositionerV6; - vtable?for?mir::wayland::XdgPositionerV6; - typeinfo?for?mir::wayland::XdgPositionerV6::Global; - vtable?for?mir::wayland::XdgPositionerV6::Global; - - mir::wayland::XdgShellV6::*; - non-virtual?thunk?to?mir::wayland::XdgShellV6::*; - typeinfo?for?mir::wayland::XdgShellV6; - vtable?for?mir::wayland::XdgShellV6; - typeinfo?for?mir::wayland::XdgShellV6::Global; - vtable?for?mir::wayland::XdgShellV6::Global; - - mir::wayland::XdgSurface::*; - non-virtual?thunk?to?mir::wayland::XdgSurface::*; - typeinfo?for?mir::wayland::XdgSurface; - vtable?for?mir::wayland::XdgSurface; - typeinfo?for?mir::wayland::XdgSurface::Global; - vtable?for?mir::wayland::XdgSurface::Global; - - mir::wayland::XdgSurfaceV6::*; - non-virtual?thunk?to?mir::wayland::XdgSurfaceV6::*; - typeinfo?for?mir::wayland::XdgSurfaceV6; - vtable?for?mir::wayland::XdgSurfaceV6; - typeinfo?for?mir::wayland::XdgSurfaceV6::Global; - vtable?for?mir::wayland::XdgSurfaceV6::Global; - - mir::wayland::XdgToplevel::*; - non-virtual?thunk?to?mir::wayland::XdgToplevel::*; - typeinfo?for?mir::wayland::XdgToplevel; - vtable?for?mir::wayland::XdgToplevel; - typeinfo?for?mir::wayland::XdgToplevel::Global; - vtable?for?mir::wayland::XdgToplevel::Global; - - mir::wayland::XdgToplevelV6::*; - non-virtual?thunk?to?mir::wayland::XdgToplevelV6::*; - typeinfo?for?mir::wayland::XdgToplevelV6; - vtable?for?mir::wayland::XdgToplevelV6; - typeinfo?for?mir::wayland::XdgToplevelV6::Global; - vtable?for?mir::wayland::XdgToplevelV6::Global; - - mir::wayland::XdgWmBase::*; - non-virtual?thunk?to?mir::wayland::XdgWmBase::*; - typeinfo?for?mir::wayland::XdgWmBase; - vtable?for?mir::wayland::XdgWmBase; - typeinfo?for?mir::wayland::XdgWmBase::Global; - vtable?for?mir::wayland::XdgWmBase::Global; - - mir::wayland::XdgOutputManagerV1::*; - non-virtual?thunk?to?mir::wayland::XdgOutputManagerV1::*; - typeinfo?for?mir::wayland::XdgOutputManagerV1; - vtable?for?mir::wayland::XdgOutputManagerV1; - typeinfo?for?mir::wayland::XdgOutputManagerV1::Global; - vtable?for?mir::wayland::XdgOutputManagerV1::Global; - - mir::wayland::XdgOutputV1::*; - non-virtual?thunk?to?mir::wayland::XdgOutputV1::*; - typeinfo?for?mir::wayland::XdgOutputV1; - vtable?for?mir::wayland::XdgOutputV1; - typeinfo?for?mir::wayland::XdgOutputV1::Global; - vtable?for?mir::wayland::XdgOutputV1::Global; - - mir::wayland::wl_buffer_interface_data; - mir::wayland::wl_callback_interface_data; - mir::wayland::wl_compositor_interface_data; - mir::wayland::wl_data_device_interface_data; - mir::wayland::wl_data_device_manager_interface_data; - mir::wayland::wl_data_offer_interface_data; - mir::wayland::wl_data_source_interface_data; - mir::wayland::wl_keyboard_interface_data; - mir::wayland::wl_output_interface_data; - mir::wayland::wl_output_interface_data; - mir::wayland::wl_output_interface_data; - mir::wayland::wl_output_interface_data; - mir::wayland::wl_pointer_interface_data; - mir::wayland::wl_region_interface_data; - mir::wayland::wl_seat_interface_data; - mir::wayland::wl_seat_interface_data; - mir::wayland::wl_seat_interface_data; - mir::wayland::wl_shell_interface_data; - mir::wayland::wl_shell_surface_interface_data; - mir::wayland::wl_shm_interface_data; - mir::wayland::wl_shm_pool_interface_data; - mir::wayland::wl_subcompositor_interface_data; - mir::wayland::wl_subsurface_interface_data; - mir::wayland::wl_surface_interface_data; - mir::wayland::wl_surface_interface_data; - mir::wayland::wl_surface_interface_data; - mir::wayland::wl_surface_interface_data; - mir::wayland::wl_touch_interface_data; - mir::wayland::xdg_popup_interface_data; - mir::wayland::xdg_popup_interface_data; - mir::wayland::xdg_positioner_interface_data; - mir::wayland::xdg_surface_interface_data; - mir::wayland::xdg_toplevel_interface_data; - mir::wayland::xdg_wm_base_interface_data; - mir::wayland::zwlr_layer_shell_v1_interface_data; - mir::wayland::zwlr_layer_surface_v1_interface_data; - mir::wayland::zxdg_popup_v6_interface_data; - mir::wayland::zxdg_positioner_v6_interface_data; - mir::wayland::zxdg_shell_v6_interface_data; - mir::wayland::zxdg_surface_v6_interface_data; - mir::wayland::zxdg_toplevel_v6_interface_data; - mir::wayland::zxdg_output_v1_interface_data; - mir::wayland::zxdg_output_manager_v1_interface_data; - - mir::wayland::LifetimeTracker::*; - typeinfo?for?mir::wayland::LifetimeTracker; - vtable?for?mir::wayland::LifetimeTracker; - - mir::wayland::Resource::*; - typeinfo?for?mir::wayland::Resource; - vtable?for?mir::wayland::Resource; - - mir::wayland::Global::*; - typeinfo?for?mir::wayland::Global; - vtable?for?mir::wayland::Global; - - mir::wayland::internal_error_processing_request*; - - # Thunks needed in clang builds - virtual?thunk?to?mir::wayland::Callback::?Callback*; - virtual?thunk?to?mir::wayland::Compositor::?Compositor*; - virtual?thunk?to?mir::wayland::DataDevice::?DataDevice*; - virtual?thunk?to?mir::wayland::DataDeviceManager::?DataDeviceManager*; - virtual?thunk?to?mir::wayland::DataOffer::?DataOffer*; - virtual?thunk?to?mir::wayland::DataSource::?DataSource*; - virtual?thunk?to?mir::wayland::Keyboard::?Keyboard*; - virtual?thunk?to?mir::wayland::LayerShellV1::?LayerShellV1*; - virtual?thunk?to?mir::wayland::LayerSurfaceV1::?LayerSurfaceV1*; - virtual?thunk?to?mir::wayland::Pointer::?Pointer*; - virtual?thunk?to?mir::wayland::Region::?Region*; - virtual?thunk?to?mir::wayland::Seat::?Seat*; - virtual?thunk?to?mir::wayland::Shell::?Shell*; - virtual?thunk?to?mir::wayland::ShellSurface::?ShellSurface*; - virtual?thunk?to?mir::wayland::Subcompositor::?Subcompositor*; - virtual?thunk?to?mir::wayland::Subsurface::?Subsurface*; - virtual?thunk?to?mir::wayland::Surface::?Surface*; - virtual?thunk?to?mir::wayland::Touch::?Touch*; - virtual?thunk?to?mir::wayland::XdgOutputManagerV1::?XdgOutputManagerV1*; - virtual?thunk?to?mir::wayland::XdgOutputV1::?XdgOutputV1*; - virtual?thunk?to?mir::wayland::XdgPopupV6::?XdgPopupV6*; - virtual?thunk?to?mir::wayland::XdgPopup::?XdgPopup*; - virtual?thunk?to?mir::wayland::XdgPositionerV6::?XdgPositionerV6*; - virtual?thunk?to?mir::wayland::XdgPositioner::?XdgPositioner*; - virtual?thunk?to?mir::wayland::XdgShellV6::?XdgShellV6*; - virtual?thunk?to?mir::wayland::XdgSurfaceV6::?XdgSurfaceV6*; - virtual?thunk?to?mir::wayland::XdgSurface::?XdgSurface*; - virtual?thunk?to?mir::wayland::XdgToplevelV6::?XdgToplevelV6*; - virtual?thunk?to?mir::wayland::XdgToplevel::?XdgToplevel*; - virtual?thunk?to?mir::wayland::XdgWmBase::?XdgWmBase*; - - mir::wayland::ForeignToplevelManagerV1::*; - non-virtual?thunk?to?mir::wayland::ForeignToplevelManagerV1::*; - virtual?thunk?to?mir::wayland::ForeignToplevelManagerV1::?ForeignToplevelManagerV1*; - typeinfo?for?mir::wayland::ForeignToplevelManagerV1; - vtable?for?mir::wayland::ForeignToplevelManagerV1; - typeinfo?for?mir::wayland::ForeignToplevelManagerV1::Global; - vtable?for?mir::wayland::ForeignToplevelManagerV1::Global; - mir::wayland::zwlr_foreign_toplevel_handle_v1_interface_data; - - mir::wayland::ForeignToplevelHandleV1::*; - non-virtual?thunk?to?mir::wayland::ForeignToplevelHandleV1::*; - virtual?thunk?to?mir::wayland::ForeignToplevelHandleV1::?ForeignToplevelHandleV1*; - typeinfo?for?mir::wayland::ForeignToplevelHandleV1; - vtable?for?mir::wayland::ForeignToplevelHandleV1; - mir::wayland::zwlr_foreign_toplevel_manager_v1_interface_data; - - mir::wayland::ProtocolError::*; - non-virtual?thunk?to?mir::wayland::ProtocolError::*; - virtual?thunk?to?mir::wayland::ProtocolError::?ProtocolError*; - mir::wayland::ProtocolError::message*; - mir::wayland::ProtocolError::code*; - mir::wayland::ProtocolError::resource*; - typeinfo?for?mir::wayland::ProtocolError; - vtable?for?mir::wayland::ProtocolError; - - mir::wayland::PointerConstraintsV1::*; - non-virtual?thunk?to?mir::wayland::PointerConstraintsV1::*; - typeinfo?for?mir::wayland::PointerConstraintsV1; - vtable?for?mir::wayland::PointerConstraintsV1; - typeinfo?for?mir::wayland::PointerConstraintsV1::Global; - vtable?for?mir::wayland::PointerConstraintsV1::Global; - virtual?thunk?to?mir::wayland::PointerConstraintsV1::?PointerConstraintsV1*; - - mir::wayland::ConfinedPointerV1::*; - non-virtual?thunk?to?mir::wayland::ConfinedPointerV1::*; - typeinfo?for?mir::wayland::ConfinedPointerV1; - vtable?for?mir::wayland::ConfinedPointerV1; - virtual?thunk?to?mir::wayland::ConfinedPointerV1::?ConfinedPointerV1*; - - mir::wayland::LockedPointerV1::*; - non-virtual?thunk?to?mir::wayland::LockedPointerV1::*; - typeinfo?for?mir::wayland::LockedPointerV1; - vtable?for?mir::wayland::LockedPointerV1; - virtual?thunk?to?mir::wayland::LockedPointerV1::?LockedPointerV1*; - - mir::wayland::RelativePointerManagerV1::*; - non-virtual?thunk?to?mir::wayland::RelativePointerManagerV1::*; - typeinfo?for?mir::wayland::RelativePointerManagerV1; - vtable?for?mir::wayland::RelativePointerManagerV1; - typeinfo?for?mir::wayland::RelativePointerManagerV1::Global; - vtable?for?mir::wayland::RelativePointerManagerV1::Global; - virtual?thunk?to?mir::wayland::RelativePointerManagerV1::?RelativePointerManagerV1*; - - mir::wayland::RelativePointerV1::*; - non-virtual?thunk?to?mir::wayland::RelativePointerV1::*; - typeinfo?for?mir::wayland::RelativePointerV1; - vtable?for?mir::wayland::RelativePointerV1; - virtual?thunk?to?mir::wayland::RelativePointerV1::?RelativePointerV1*; - - mir::wayland::VirtualKeyboardManagerV1::*; - non-virtual?thunk?to?mir::wayland::VirtualKeyboardManagerV1::*; - typeinfo?for?mir::wayland::VirtualKeyboardManagerV1; - vtable?for?mir::wayland::VirtualKeyboardManagerV1; - typeinfo?for?mir::wayland::VirtualKeyboardManagerV1::Global; - vtable?for?mir::wayland::VirtualKeyboardManagerV1::Global; - virtual?thunk?to?mir::wayland::VirtualKeyboardManagerV1::?VirtualKeyboardManagerV1*; - - mir::wayland::VirtualKeyboardV1::*; - non-virtual?thunk?to?mir::wayland::VirtualKeyboardV1::*; - typeinfo?for?mir::wayland::VirtualKeyboardV1; - vtable?for?mir::wayland::VirtualKeyboardV1; - virtual?thunk?to?mir::wayland::VirtualKeyboardV1::?VirtualKeyboardV1*; - - mir::wayland::TextInputManagerV2::*; - non-virtual?thunk?to?mir::wayland::TextInputManagerV2::*; - typeinfo?for?mir::wayland::TextInputManagerV2; - vtable?for?mir::wayland::TextInputManagerV2; - typeinfo?for?mir::wayland::TextInputManagerV2::Global; - vtable?for?mir::wayland::TextInputManagerV2::Global; - virtual?thunk?to?mir::wayland::TextInputManagerV2::?TextInputManagerV2*; - - mir::wayland::TextInputV2::*; - non-virtual?thunk?to?mir::wayland::TextInputV2::*; - typeinfo?for?mir::wayland::TextInputV2; - vtable?for?mir::wayland::TextInputV2; - virtual?thunk?to?mir::wayland::TextInputV2::?TextInputV2*; - - mir::wayland::TextInputManagerV3::*; - non-virtual?thunk?to?mir::wayland::TextInputManagerV3::*; - typeinfo?for?mir::wayland::TextInputManagerV3; - vtable?for?mir::wayland::TextInputManagerV3; - typeinfo?for?mir::wayland::TextInputManagerV3::Global; - vtable?for?mir::wayland::TextInputManagerV3::Global; - virtual?thunk?to?mir::wayland::TextInputManagerV3::?TextInputManagerV3*; - - mir::wayland::TextInputV3::*; - non-virtual?thunk?to?mir::wayland::TextInputV3::*; - typeinfo?for?mir::wayland::TextInputV3; - vtable?for?mir::wayland::TextInputV3; - virtual?thunk?to?mir::wayland::TextInputV3::?TextInputV3*; - - mir::wayland::InputMethodManagerV2::*; - non-virtual?thunk?to?mir::wayland::InputMethodManagerV2::*; - typeinfo?for?mir::wayland::InputMethodManagerV2; - vtable?for?mir::wayland::InputMethodManagerV2; - typeinfo?for?mir::wayland::InputMethodManagerV2::Global; - vtable?for?mir::wayland::InputMethodManagerV2::Global; - virtual?thunk?to?mir::wayland::InputMethodManagerV2::?InputMethodManagerV2*; - - mir::wayland::InputMethodV2::*; - non-virtual?thunk?to?mir::wayland::InputMethodV2::*; - typeinfo?for?mir::wayland::InputMethodV2; - vtable?for?mir::wayland::InputMethodV2; - virtual?thunk?to?mir::wayland::InputMethodV2::?InputMethodV2*; - - mir::wayland::InputPopupSurfaceV2::*; - non-virtual?thunk?to?mir::wayland::InputPopupSurfaceV2::*; - typeinfo?for?mir::wayland::InputPopupSurfaceV2; - vtable?for?mir::wayland::InputPopupSurfaceV2; - virtual?thunk?to?mir::wayland::InputPopupSurfaceV2::?InputPopupSurfaceV2*; - - mir::wayland::InputMethodKeyboardGrabV2::*; - non-virtual?thunk?to?mir::wayland::InputMethodKeyboardGrabV2::*; - typeinfo?for?mir::wayland::InputMethodKeyboardGrabV2; - vtable?for?mir::wayland::InputMethodKeyboardGrabV2; - virtual?thunk?to?mir::wayland::InputMethodKeyboardGrabV2::?InputMethodKeyboardGrabV2*; - - mir::wayland::WlrScreencopyManagerV1::*; - non-virtual?thunk?to?mir::wayland::WlrScreencopyManagerV1::*; - typeinfo?for?mir::wayland::WlrScreencopyManagerV1; - vtable?for?mir::wayland::WlrScreencopyManagerV1; - typeinfo?for?mir::wayland::WlrScreencopyManagerV1::Global; - vtable?for?mir::wayland::WlrScreencopyManagerV1::Global; - virtual?thunk?to?mir::wayland::WlrScreencopyManagerV1::?WlrScreencopyManagerV1*; - - mir::wayland::WlrScreencopyFrameV1::*; - non-virtual?thunk?to?mir::wayland::WlrScreencopyFrameV1::*; - typeinfo?for?mir::wayland::WlrScreencopyFrameV1; - vtable?for?mir::wayland::WlrScreencopyFrameV1; - virtual?thunk?to?mir::wayland::WlrScreencopyFrameV1::?WlrScreencopyFrameV1*; - - mir::wayland::IdleInhibitManagerV1::*; - non-virtual?thunk?to?mir::wayland::IdleInhibitManagerV1::*; - typeinfo?for?mir::wayland::IdleInhibitManagerV1; - vtable?for?mir::wayland::IdleInhibitManagerV1; - typeinfo?for?mir::wayland::IdleInhibitManagerV1::Global; - vtable?for?mir::wayland::IdleInhibitManagerV1::Global; - virtual?thunk?to?mir::wayland::IdleInhibitManagerV1::?IdleInhibitManagerV1*; - - mir::wayland::IdleInhibitorV1::*; - non-virtual?thunk?to?mir::wayland::IdleInhibitorV1::*; - typeinfo?for?mir::wayland::IdleInhibitorV1; - vtable?for?mir::wayland::IdleInhibitorV1; - virtual?thunk?to?mir::wayland::IdleInhibitorV1::?IdleInhibitorV1*; - - mir::wayland::tried_to_send_unsupported_event*; - mir::wayland::TextInputManagerV1::*; - non-virtual?thunk?to?mir::wayland::TextInputManagerV1::*; - typeinfo?for?mir::wayland::TextInputManagerV1; - vtable?for?mir::wayland::TextInputManagerV1; - typeinfo?for?mir::wayland::TextInputManagerV1::Global; - vtable?for?mir::wayland::TextInputManagerV1::Global; - virtual?thunk?to?mir::wayland::TextInputManagerV1::?TextInputManagerV1*; - - mir::wayland::TextInputV1::*; - non-virtual?thunk?to?mir::wayland::TextInputV1::*; - typeinfo?for?mir::wayland::TextInputV1; - vtable?for?mir::wayland::TextInputV1; - virtual?thunk?to?mir::wayland::TextInputV1::?TextInputV1*; - - virtual?thunk?to?mir::wayland::Output::?Output*; - - mir::wayland::VirtualPointerManagerV1::*; - non-virtual?thunk?to?mir::wayland::VirtualPointerManagerV1::*; - typeinfo?for?mir::wayland::VirtualPointerManagerV1; - vtable?for?mir::wayland::VirtualPointerManagerV1; - typeinfo?for?mir::wayland::VirtualPointerManagerV1::Global; - vtable?for?mir::wayland::VirtualPointerManagerV1::Global; - virtual?thunk?to?mir::wayland::VirtualPointerManagerV1::?VirtualPointerManagerV1*; - - mir::wayland::VirtualPointerV1::*; - non-virtual?thunk?to?mir::wayland::VirtualPointerV1::*; - typeinfo?for?mir::wayland::VirtualPointerV1; - vtable?for?mir::wayland::VirtualPointerV1; - virtual?thunk?to?mir::wayland::VirtualPointerV1::?VirtualPointerV1*; - - mir::wayland::Client::from*; - mir::wayland::Client::register_client*; - mir::wayland::Client::unregister_client*; - virtual?thunk?to?mir::wayland::Resource::?Resource*; - - mir::wayland::PrimarySelectionDeviceManagerV1::*; - non-virtual?thunk?to?mir::wayland::PrimarySelectionDeviceManagerV1::*; - typeinfo?for?mir::wayland::PrimarySelectionDeviceManagerV1; - vtable?for?mir::wayland::PrimarySelectionDeviceManagerV1; - typeinfo?for?mir::wayland::PrimarySelectionDeviceManagerV1::Global; - vtable?for?mir::wayland::PrimarySelectionDeviceManagerV1::Global; - virtual?thunk?to?mir::wayland::PrimarySelectionDeviceManagerV1::?PrimarySelectionDeviceManagerV1*; - - mir::wayland::PrimarySelectionDeviceV1::*; - non-virtual?thunk?to?mir::wayland::PrimarySelectionDeviceV1::*; - typeinfo?for?mir::wayland::PrimarySelectionDeviceV1; - vtable?for?mir::wayland::PrimarySelectionDeviceV1; - virtual?thunk?to?mir::wayland::PrimarySelectionDeviceV1::?PrimarySelectionDeviceV1*; - - mir::wayland::PrimarySelectionOfferV1::*; - non-virtual?thunk?to?mir::wayland::PrimarySelectionOfferV1::*; - typeinfo?for?mir::wayland::PrimarySelectionOfferV1; - vtable?for?mir::wayland::PrimarySelectionOfferV1; - virtual?thunk?to?mir::wayland::PrimarySelectionOfferV1::?PrimarySelectionOfferV1*; - - mir::wayland::PrimarySelectionSourceV1::*; - non-virtual?thunk?to?mir::wayland::PrimarySelectionSourceV1::*; - typeinfo?for?mir::wayland::PrimarySelectionSourceV1; - vtable?for?mir::wayland::PrimarySelectionSourceV1; - virtual?thunk?to?mir::wayland::PrimarySelectionSourceV1::?PrimarySelectionSourceV1*; - - mir::wayland::Shm::*; - non-virtual?thunk?to?mir::wayland::Shm::*; - typeinfo?for?mir::wayland::Shm; - vtable?for?mir::wayland::Shm; - virtual?thunk?to?mir::wayland::Shm::?Shm*; - - mir::wayland::ShmPool::*; - non-virtual?thunk?to?mir::wayland::ShmPool::*; - typeinfo?for?mir::wayland::ShmPool; - vtable?for?mir::wayland::ShmPool; - virtual?thunk?to?mir::wayland::ShmPool::?ShmPool*; - - mir::wayland::SessionLockManagerV1::*; - non-virtual?thunk?to?mir::wayland::SessionLockManagerV1::*; - typeinfo?for?mir::wayland::SessionLockManagerV1; - vtable?for?mir::wayland::SessionLockManagerV1; - typeinfo?for?mir::wayland::SessionLockManagerV1::Global; - vtable?for?mir::wayland::SessionLockManagerV1::Global; - virtual?thunk?to?mir::wayland::SessionLockManagerV1::?SessionLockManagerV1*; - - mir::wayland::SessionLockV1::*; - non-virtual?thunk?to?mir::wayland::SessionLockV1::*; - typeinfo?for?mir::wayland::SessionLockV1; - vtable?for?mir::wayland::SessionLockV1; - virtual?thunk?to?mir::wayland::SessionLockV1::?SessionLockV1*; - - mir::wayland::SessionLockSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::SessionLockSurfaceV1::*; - typeinfo?for?mir::wayland::SessionLockSurfaceV1; - vtable?for?mir::wayland::SessionLockSurfaceV1; - virtual?thunk?to?mir::wayland::SessionLockSurfaceV1::?SessionLockSurfaceV1*; - - mir::wayland::InputMethodV1::*; - non-virtual?thunk?to?mir::wayland::InputMethodV1::*; - virtual?thunk?to?mir::wayland::InputMethodV1::*; - typeinfo?for?mir::wayland::InputMethodV1; - vtable?for?mir::wayland::InputMethodV1; - typeinfo?for?mir::wayland::InputMethodV1::Global; - vtable?for?mir::wayland::InputMethodV1::Global; - - mir::wayland::InputMethodContextV1::*; - non-virtual?thunk?to?mir::wayland::InputMethodContextV1::*; - virtual?thunk?to?mir::wayland::InputMethodContextV1::*; - typeinfo?for?mir::wayland::InputMethodContextV1; - vtable?for?mir::wayland::InputMethodContextV1; - - mir::wayland::InputPanelV1::*; - non-virtual?thunk?to?mir::wayland::InputPanelV1::*; - virtual?thunk?to?mir::wayland::InputPanelV1::*; - typeinfo?for?mir::wayland::InputPanelV1; - vtable?for?mir::wayland::InputPanelV1; - typeinfo?for?mir::wayland::InputPanelV1::Global; - vtable?for?mir::wayland::InputPanelV1::Global; - - mir::wayland::InputPanelSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::InputPanelSurfaceV1::*; - virtual?thunk?to?mir::wayland::InputPanelSurfaceV1::*; - typeinfo?for?mir::wayland::InputPanelSurfaceV1; - vtable?for?mir::wayland::InputPanelSurfaceV1; - - mir::wayland::MirShellV1::*; - non-virtual?thunk?to?mir::wayland::MirShellV1::*; - virtual?thunk?to?mir::wayland::MirShellV1::*; - typeinfo?for?mir::wayland::MirShellV1; - vtable?for?mir::wayland::MirShellV1; - typeinfo?for?mir::wayland::MirShellV1::Global; - vtable?for?mir::wayland::MirShellV1::Global; - - mir::wayland::MirRegularSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::MirRegularSurfaceV1::*; - virtual?thunk?to?mir::wayland::MirRegularSurfaceV1::*; - typeinfo?for?mir::wayland::MirRegularSurfaceV1; - vtable?for?mir::wayland::MirRegularSurfaceV1; - - mir::wayland::MirFloatingRegularSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::MirFloatingRegularSurfaceV1::*; - virtual?thunk?to?mir::wayland::MirFloatingRegularSurfaceV1::*; - typeinfo?for?mir::wayland::MirFloatingRegularSurfaceV1; - vtable?for?mir::wayland::MirFloatingRegularSurfaceV1; - - mir::wayland::MirDialogSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::MirDialogSurfaceV1::*; - virtual?thunk?to?mir::wayland::MirDialogSurfaceV1::*; - typeinfo?for?mir::wayland::MirDialogSurfaceV1; - vtable?for?mir::wayland::MirDialogSurfaceV1; - - mir::wayland::MirSatelliteSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::MirSatelliteSurfaceV1::*; - virtual?thunk?to?mir::wayland::MirSatelliteSurfaceV1::*; - typeinfo?for?mir::wayland::MirSatelliteSurfaceV1; - vtable?for?mir::wayland::MirSatelliteSurfaceV1; - - mir::wayland::MirFreestyleSurfaceV1::*; - non-virtual?thunk?to?mir::wayland::MirFreestyleSurfaceV1::*; - virtual?thunk?to?mir::wayland::MirFreestyleSurfaceV1::*; - typeinfo?for?mir::wayland::MirFreestyleSurfaceV1; - vtable?for?mir::wayland::MirFreestyleSurfaceV1; - - mir::wayland::MirPositionerV1::*; - non-virtual?thunk?to?mir::wayland::MirPositionerV1::*; - virtual?thunk?to?mir::wayland::MirPositionerV1::*; - typeinfo?for?mir::wayland::MirPositionerV1; - vtable?for?mir::wayland::MirPositionerV1; - }; -};