diff --git a/wayland_adapter/BUILD.gn b/wayland_adapter/BUILD.gn index cbd984951c8e82a9e7324e88f0c9bc3489b826e4..72b7d361f37a3907864750314b765ded4f7b9548 100644 --- a/wayland_adapter/BUILD.gn +++ b/wayland_adapter/BUILD.gn @@ -17,7 +17,10 @@ import("//config.gni") config("libwayland_adapter_config") { visibility = [ ":*" ] - cflags = [ "-Wno-c++11-narrowing" ] + cflags = [ + "-Wno-c++11-narrowing", + "-Wno-c++20-extensions", + ] include_dirs = [ "utils", @@ -38,5 +41,6 @@ ft_shared_library("libwayland_adapter") { "//build/gn/configs/system_libs:hilog", "//build/gn/configs/system_libs:safwk", "//display_server/drivers/hal/base:ft_event_loop", + "//wayland_adapter/utils:wayland_adapter_utils_sources", ] } diff --git a/wayland_adapter/utils/BUILD.gn b/wayland_adapter/utils/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2c6977bfc9764613e39d78dc32dd85d78f0ab2aa --- /dev/null +++ b/wayland_adapter/utils/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright (c) 2023 Huawei Technologies Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/gn/fangtian.gni") +import("//config.gni") + +config("wayland_utils_public_config") { + include_dirs = [ "include" ] +} + +ft_source_set("wayland_adapter_utils_sources") { + sources = [ + "src/wayland_global.cpp", + "src/wayland_objects_pool.cpp", + "src/wayland_resource_object.cpp", + ] + + public_configs = [ ":wayland_utils_public_config" ] + + deps = [ + "//build/gn/configs/system_libs:hilog", + "//display_server/drivers/hal/base:ft_event_loop", + ] +} diff --git a/wayland_adapter/utils/wayland_adapter_hilog.h b/wayland_adapter/utils/include/wayland_adapter_hilog.h similarity index 100% rename from wayland_adapter/utils/wayland_adapter_hilog.h rename to wayland_adapter/utils/include/wayland_adapter_hilog.h diff --git a/wayland_adapter/utils/include/wayland_global.h b/wayland_adapter/utils/include/wayland_global.h new file mode 100644 index 0000000000000000000000000000000000000000..97e33e07c495f0549aecf48fd6edb0064677e2dd --- /dev/null +++ b/wayland_adapter/utils/include/wayland_global.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "wayland_resource_object.h" + +namespace FT { +namespace Wayland { +class WaylandGlobal : NonCopyable, public OHOS::RefBase { +public: + virtual ~WaylandGlobal() noexcept override; + + const std::string &Name() const + { + return name_; + } + uint32_t MaxSupportVersion() const + { + return maxSupportVersion_; + } + +protected: + WaylandGlobal(struct wl_display *display, const struct wl_interface *interface, uint32_t maxSupportVersion); + static void BindCallback(struct wl_client *client, void *data, uint32_t version, uint32_t id); + virtual void Bind(struct wl_client *client, uint32_t version, uint32_t id) = 0; + + std::string name_; + uint32_t maxSupportVersion_ = 0; + struct wl_display *display_ = nullptr; + const struct wl_interface *interface_ = nullptr; + struct wl_global *global_ = nullptr; +}; +} // namespace Wayland +} // namespace FT diff --git a/wayland_adapter/utils/include/wayland_objects_pool.h b/wayland_adapter/utils/include/wayland_objects_pool.h new file mode 100644 index 0000000000000000000000000000000000000000..ef8a3d084cd79987977ffe48f1ba2e07837514dd --- /dev/null +++ b/wayland_adapter/utils/include/wayland_objects_pool.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include "wayland_singleton.h" +#include "wayland_resource_object.h" + +namespace FT { +namespace Wayland { +class WaylandObjectsPoolCallback : public OHOS::RefBase { +public: + virtual void OnDestroy(ObjectId objectId) {} +}; + +class WaylandObjectsPool : public Singleton { + DECLARE_SINGLETON(WaylandObjectsPool) + +public: + static void SetCallback(OHOS::sptr cb); + void AddObject(ObjectId id, const OHOS::sptr &object); + void RemoveObject(ObjectId id, const OHOS::sptr &object); + OHOS::sptr GetObject(ObjectId id) const; + +private: + WaylandObjectsPool() = default; + ~WaylandObjectsPool() noexcept override = default; + + static OHOS::sptr cb_; + mutable std::mutex mutex_; + std::map> objects_; +}; +} // namespace Wayland +} // namespace FT diff --git a/wayland_adapter/utils/include/wayland_resource_object.h b/wayland_adapter/utils/include/wayland_resource_object.h new file mode 100644 index 0000000000000000000000000000000000000000..e3b969396b1bb8166775c7d8a323f41ed67e355c --- /dev/null +++ b/wayland_adapter/utils/include/wayland_resource_object.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "wayland-server-core.h" +#include "wayland_adapter_hilog.h" +#include "noncopyable_hal.h" +#include "refbase.h" +#include "types.h" + +namespace FT { +namespace Wayland { +struct ObjectId { + ObjectId(struct wl_client *client, uint32_t id) : client(client), id(id) {} + ~ObjectId() noexcept = default; + + ObjectId(const ObjectId &other) = default; + ObjectId &operator=(const ObjectId &other) = default; + + ObjectId(ObjectId &&other) noexcept : client(other.client), id(other.id) + { + other.client = nullptr; + other.id = 0; + } + ObjectId &operator=(ObjectId &&other) noexcept + { + client = other.client; + id = other.id; + other.client = nullptr; + other.id = 0; + return *this; + } + bool operator<(const ObjectId &other) const + { + if (client != other.client) { + return client < other.client; + } + return id < other.id; + } + bool operator==(const ObjectId &other) const + { + return client == other.client && id == other.id; + } + bool operator!=(const ObjectId &other) const + { + return !(*this == other); + } + + struct wl_client *client = nullptr; + uint32_t id = 0; +}; + +template +inline OutStream &operator<<(OutStream &os, const ObjectId &objId) +{ + os << "ObjectId(client: " << objId.client << ", id: " << objId.id << ")"; + return os; +} + +class WaylandResourceObject : NonCopyable, virtual public OHOS::RefBase { +public: + WaylandResourceObject(struct wl_client *client, const struct wl_interface *interface, + uint32_t version, uint32_t id, void *implementation); + virtual ~WaylandResourceObject() noexcept override; + + const std::string &Name() const + { + return name_; + } + uint32_t Id() const + { + return id_; + } + uint32_t Version() const + { + return version_; + } + struct wl_client *WlClient() const + { + return client_; + } + struct wl_display *WlDisplay() const + { + return display_; + } + struct wl_resource *WlResource() const + { + return resource_; + } + + static bool CheckIfObjectIsValid(const OHOS::sptr &object); + static void DefaultDestroyResource(struct wl_client *client, struct wl_resource *resource); + +protected: + static void OnDestroy(struct wl_resource *resource); + virtual void OnResourceDestroy() {} + + struct wl_client *client_ = nullptr; + struct wl_display *display_ = nullptr; + const struct wl_interface *interface_ = nullptr; + uint32_t version_ = 0; + uint32_t id_ = 0; + void *implementation_ = nullptr; + std::string name_; + struct wl_resource *resource_ = nullptr; +}; + +namespace detail { +template +struct HasFuncDefaultDestroyResource { + template + static char check(decltype(&U::DefaultDestroyResource)); + template + static int32_t check(...); + const static bool value = sizeof(check(0)) == sizeof(char); +}; +} // detail + +template +inline OHOS::sptr CastFromResource(struct wl_resource *resource) +{ + if (resource == nullptr) { + return nullptr; + } + + static_assert(detail::HasFuncDefaultDestroyResource::value, + "Can't cast wl_resource to the type which is neither ResourceObject nor the derived type of it."); + + auto wptrObj = OHOS::wptr(DownCast(wl_resource_get_user_data(resource))); + return wptrObj.promote(); +} + +#define OBJECT_CHECK(object, errlog) \ + if (!WaylandResourceObject::CheckIfObjectIsValid(object)) { \ + LOG_WARN(errlog); \ + return; \ + } + +#define CAST_OBJECT_AND_CALL_FUNC(objectType, resource, errlog, func, args...) \ + auto object = CastFromResource((resource)); \ + OBJECT_CHECK(object, errlog); \ + object->func(args); +} // namespace Wayland +} // namespace FT diff --git a/wayland_adapter/utils/include/wayland_singleton.h b/wayland_adapter/utils/include/wayland_singleton.h new file mode 100644 index 0000000000000000000000000000000000000000..4c87d597e73938bb521bbad1fb9cbbcab4ac13c4 --- /dev/null +++ b/wayland_adapter/utils/include/wayland_singleton.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "types.h" +#include "noncopyable_hal.h" + +#include + +namespace FT { +template +class Singleton : NonCopyable { +public: + Singleton() = default; + virtual ~Singleton() noexcept = default; + + static T &GetInstance() + { + std::call_once(onceFlag_, CreateInstance); + ASSERT(instance_ != nullptr); + return *instance_; + } + +private: + template + struct HasFuncDontDestroyMe { + template + static char check(decltype(&V::DontDestroyMe)); + template + static int32_t check(...); + const static bool value = sizeof(check(0)) == sizeof(char); + }; + + static void CreateInstance() + { + instance_ = new T(); + if (!HasFuncDontDestroyMe::value) { + ::atexit(DestoryInstance); + } + } + static void DestoryInstance() + { + static_assert(sizeof(T) != 0, "Singleton type T must be complete type."); + delete instance_; + instance_ = nullptr; + } + static std::once_flag onceFlag_; + static T *instance_; +}; + +template +std::once_flag Singleton::onceFlag_; + +template +T *Singleton::instance_ = nullptr; + +#define DECLARE_SINGLETON(T) \ +private: \ + friend class Singleton; +} // namespace FT diff --git a/wayland_adapter/utils/src/wayland_global.cpp b/wayland_adapter/utils/src/wayland_global.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4c14f0b7cf6f64d792936e67de267a175e82aaf --- /dev/null +++ b/wayland_adapter/utils/src/wayland_global.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wayland_global.h" + +namespace FT { +namespace Wayland { +namespace { + constexpr HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WAYLAND, "WaylandGlobal"}; +} + +WaylandGlobal::WaylandGlobal(struct wl_display *display, const struct wl_interface *interface, uint32_t maxSupportVersion) + : display_(display), + interface_(interface), + maxSupportVersion_(maxSupportVersion), + global_(wl_global_create(display_, interface_, maxSupportVersion_, this, &WaylandGlobal::BindCallback)) +{ + name_ = std::string(interface_->name) + "_" + std::to_string(maxSupportVersion_); +} + +WaylandGlobal::~WaylandGlobal() noexcept +{ + if (global_ != nullptr) { + wl_global_destroy(global_); + } +} + +void WaylandGlobal::BindCallback(struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + if (client == nullptr) { + LOG_ERROR("wl_client is nullptr"); + return; + } + + auto global = OHOS::sptr(static_cast(data)); + if (global == nullptr) { + LOG_ERROR("BindCallback failed"); + return; + } + + if (version > global->MaxSupportVersion()) { + LOG_ERROR("Unsupported version"); + return; + } + + global->Bind(client, version, id); +} +} // namespace Wayland +} // namespace FT diff --git a/wayland_adapter/utils/src/wayland_objects_pool.cpp b/wayland_adapter/utils/src/wayland_objects_pool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3eddebd069e0d750b54d6f96d12062c82ab42c2f --- /dev/null +++ b/wayland_adapter/utils/src/wayland_objects_pool.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wayland_objects_pool.h" + +namespace FT { +namespace Wayland { +namespace { + constexpr HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WAYLAND, "WaylandObjectsPool"}; +} + +OHOS::sptr WaylandObjectsPool::cb_ = nullptr; +void WaylandObjectsPool::SetCallback(OHOS::sptr cb) +{ + cb_ = cb; +} + +void WaylandObjectsPool::AddObject(ObjectId id, const OHOS::sptr &object) +{ + std::lock_guard lock(mutex_); + if (objects_.count(id) > 0) { + LOG_WARN("object already exists"); + } + + objects_[id] = object; +} + +void WaylandObjectsPool::RemoveObject(ObjectId id, const OHOS::sptr &object) +{ + std::lock_guard lock(mutex_); + if (objects_.count(id) == 0) { + LOG_WARN("object already removed"); + return; + } + + const auto &objInPool = objects_.at(id); + if (objInPool != object) { + LOG_ERROR("invalid id"); + return; + } + + objects_.erase(id); + + if (cb_ != nullptr) { + cb_->OnDestroy(id); + } +} + +OHOS::sptr WaylandObjectsPool::GetObject(ObjectId id) const +{ + std::lock_guard lock(mutex_); + if (objects_.count(id) == 0) { + LOG_WARN("object does not exist"); + return nullptr; + } + + return objects_.at(id); +} +} // namespace Wayland +} // namespace FT diff --git a/wayland_adapter/utils/src/wayland_resource_object.cpp b/wayland_adapter/utils/src/wayland_resource_object.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b4cb8ab96f0b84f997eb5eec34ed443bf02e331 --- /dev/null +++ b/wayland_adapter/utils/src/wayland_resource_object.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023 Huawei Technologies Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wayland_resource_object.h" + +#include "wayland_objects_pool.h" + +namespace FT { +namespace Wayland { +namespace { + constexpr HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WAYLAND, "WaylandResourceObject"}; +} + +WaylandResourceObject::WaylandResourceObject(struct wl_client *client, const struct wl_interface *interface, + uint32_t version, uint32_t id, void *implementation) + : client_(client), + display_(wl_client_get_display(client_)), + interface_(interface), + version_(version), + implementation_(implementation) +{ + resource_ = wl_resource_create(client_, interface_, version_, id); + if (resource_ == nullptr) { + LOG_ERROR("no memory"); + wl_client_post_no_memory(client_); + return; + } + + id_ = wl_resource_get_id(resource_); + wl_resource_set_implementation(resource_, implementation_, this, &WaylandResourceObject::OnDestroy); + name_ = std::string(interface_->name) + "_" + std::to_string(version_) + "_" + std::to_string(id_); +} + +WaylandResourceObject::~WaylandResourceObject() noexcept +{ + if (resource_ != nullptr) { + wl_resource_destroy(resource_); + } +} + +void WaylandResourceObject::DefaultDestroyResource(struct wl_client *client, struct wl_resource *resource) +{ + auto object = CastFromResource(resource); + if (object == nullptr) { + LOG_WARN("object is nullptr"); + return; + } + + object->resource_ = nullptr; + wl_resource_destroy(resource); +} + +void WaylandResourceObject::OnDestroy(struct wl_resource *resource) +{ + auto object = CastFromResource(resource); + if (object == nullptr) { + LOG_WARN("object is nullptr"); + return; + } + + object->OnResourceDestroy(); + object->resource_ = nullptr; + WaylandObjectsPool::GetInstance().RemoveObject(ObjectId(object->WlClient(), object->Id()), object); +} + +bool WaylandResourceObject::CheckIfObjectIsValid(const OHOS::sptr &object) +{ + if (object == nullptr) { + LOG_ERROR("object is nullptr"); + return false; + } + + auto objId = ObjectId(object->WlClient(), object->Id()); + auto objInPool = WaylandObjectsPool::GetInstance().GetObject(objId); + if (objInPool != object) { + LOG_ERROR("CheckIfObjectIsValid failed"); + return false; + } + + return true; +} +} // namespace Wayland +} // namespace FT