diff --git a/CMakeLists.txt b/CMakeLists.txt index 82084a3..fd55c80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,14 +289,8 @@ elseif(LINUX) target_link_libraries(lib_ui PUBLIC desktop-app::lib_waylandshells - desktop-app::external_kwayland + desktop-app::external_wayland_client ) - - if (DESKTOP_APP_USE_PACKAGED) - find_package(PkgConfig REQUIRED) - pkg_check_modules(WAYLAND_CLIENT REQUIRED IMPORTED_TARGET wayland-client) - target_link_libraries(lib_ui PRIVATE PkgConfig::WAYLAND_CLIENT) - endif() endif() target_include_directories(lib_ui diff --git a/ui/platform/linux/ui_linux_wayland_integration.cpp b/ui/platform/linux/ui_linux_wayland_integration.cpp index fa21c7b..d142278 100644 --- a/ui/platform/linux/ui_linux_wayland_integration.cpp +++ b/ui/platform/linux/ui_linux_wayland_integration.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/platform/linux/ui_linux_wayland_integration.h" #include "base/platform/base_platform_info.h" +#include "base/qt_signal_producer.h" #include "waylandshells/xdg_shell.h" #include "qwayland-xdg-shell.h" @@ -25,48 +26,112 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include -#include -#include +#include Q_DECLARE_METATYPE(QMargins); using QtWaylandClient::QWaylandWindow; -using namespace KWayland::Client; namespace Ui { namespace Platform { +namespace { + +struct WlRegistryDeleter { + void operator()(wl_registry *value) { + wl_registry_destroy(value); + } +}; + +struct WlCallbackDeleter { + void operator()(wl_callback *value) { + wl_callback_destroy(value); + } +}; + +} // namespace struct WaylandIntegration::Private { - std::unique_ptr connection; - Registry registry; + std::unique_ptr registry; + std::unique_ptr callback; QEventLoop interfacesLoop; bool interfacesAnnounced = false; + bool xdgDecorationSupported = false; + uint32_t xdgDecorationName = 0; + rpl::lifetime lifetime; + + static const struct wl_registry_listener RegistryListener; + static const struct wl_callback_listener CallbackListener; +}; + +const struct wl_registry_listener WaylandIntegration::Private::RegistryListener = { + decltype(wl_registry_listener::global)(+[]( + Private *data, + wl_registry *registry, + uint32_t name, + const char *interface, + uint32_t version) { + if (interface == qstr("zxdg_decoration_manager_v1")) { + data->xdgDecorationSupported = true; + } + }), + decltype(wl_registry_listener::global_remove)(+[]( + Private *data, + wl_registry *registry, + uint32_t name) { + if (name == data->xdgDecorationName) { + data->xdgDecorationSupported = false; + } + }), +}; + +const struct wl_callback_listener WaylandIntegration::Private::CallbackListener = { + decltype(wl_callback_listener::done)(+[]( + Private *data, + wl_callback *callback, + uint32_t serial) { + data->interfacesAnnounced = true; + if (data->interfacesLoop.isRunning()) { + data->interfacesLoop.quit(); + } + data->callback = nullptr; + }), }; WaylandIntegration::WaylandIntegration() : _private(std::make_unique()) { - _private->connection = std::unique_ptr{ - ConnectionThread::fromApplication(), - }; + const auto native = QGuiApplication::platformNativeInterface(); + if (!native) { + return; + } - _private->registry.create(_private->connection.get()); - _private->registry.setup(); + const auto display = reinterpret_cast( + native->nativeResourceForIntegration(QByteArray("wl_display"))); - QObject::connect( - _private->connection.get(), - &ConnectionThread::connectionDied, - &_private->registry, - &Registry::destroy); + if (!display) { + return; + } - QObject::connect( - &_private->registry, - &Registry::interfacesAnnounced, - [=] { - _private->interfacesAnnounced = true; - if (_private->interfacesLoop.isRunning()) { - _private->interfacesLoop.quit(); - } - }); + _private->registry.reset(wl_display_get_registry(display)); + _private->callback.reset(wl_display_sync(display)); + + wl_registry_add_listener( + _private->registry.get(), + &Private::RegistryListener, + _private.get()); + + wl_callback_add_listener( + _private->callback.get(), + &Private::CallbackListener, + _private.get()); + + base::qt_signal_producer( + native, + &QObject::destroyed + ) | rpl::start_with_next([=] { + // too late for standard destructors, just free + free(_private->callback.release()); + free(_private->registry.release()); + }, _private->lifetime); } WaylandIntegration::~WaylandIntegration() = default; @@ -85,8 +150,7 @@ void WaylandIntegration::waitForInterfaceAnnounce() { } bool WaylandIntegration::xdgDecorationSupported() { - return _private->registry.hasInterface( - Registry::Interface::XdgDecorationUnstableV1); + return _private->xdgDecorationSupported; } bool WaylandIntegration::windowExtentsSupported() {