From d5a37c74b17b2c06b0d37f9a16129c70e0581c57 Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Mon, 11 Apr 2022 01:44:05 +0400 Subject: [PATCH] Try to use as less private APIs as possible to show window menu on Wayland --- CMakeLists.txt | 17 ++++++- .../linux/ui_linux_wayland_integration.cpp | 46 ++++++++++++++----- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a3ad7c..6689f2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ generate_emoji(lib_ui emoji.txt emoji_suggestions/emoji_autocomplete.json) set_target_properties(lib_ui PROPERTIES AUTOMOC ON) target_prepare_qrc(lib_ui) -target_precompile_headers(lib_ui PRIVATE ${src_loc}/ui/ui_pch.h) +target_precompile_headers(lib_ui PRIVATE $<$:${src_loc}/ui/ui_pch.h>) nice_target_sources(lib_ui ${src_loc} PRIVATE ${style_files} @@ -270,11 +270,26 @@ if (DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION) elseif(LINUX) remove_target_sources(lib_ui ${src_loc} ui/platform/linux/ui_linux_wayland_integration_dummy.cpp) + if (DESKTOP_APP_QT6) + qt6_generate_wayland_protocol_client_sources(lib_ui + FILES + ${third_party_loc}/wayland-protocols/stable/xdg-shell/xdg-shell.xml + ) + else() + message(FATAL_ERROR "This piece of cmake code is not ported to Qt 5") + endif() + target_link_libraries(lib_ui PUBLIC desktop-app::lib_waylandshells desktop-app::external_kwayland ) + + 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 01f1e80..8f9fed2 100644 --- a/ui/platform/linux/ui_linux_wayland_integration.cpp +++ b/ui/platform/linux/ui_linux_wayland_integration.cpp @@ -9,20 +9,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/platform/base_platform_info.h" #include "waylandshells/xdg_shell.h" +#include "qwayland-xdg-shell.h" +#include #include +#include +#include +#include -// private headers are using keywords :( +// private QtWaylandClient headers are using keywords :( #ifdef QT_NO_KEYWORDS #define signals Q_SIGNALS #define slots Q_SLOTS #endif // QT_NO_KEYWORDS -#include #include #include #include -#include +#include #include #include @@ -113,16 +117,36 @@ void WaylandIntegration::unsetWindowExtents(QWindow *window) { } bool WaylandIntegration::showWindowMenu(QWindow *window) { - if (const auto waylandWindow = static_cast( - window->handle())) { - if (const auto seat = waylandWindow->display()->lastInputDevice()) { - if (const auto shellSurface = waylandWindow->shellSurface()) { - return shellSurface->showWindowMenu(seat); - } - } + const auto native = QGuiApplication::platformNativeInterface(); + if (!native) { + return false; } - return false; + const auto toplevel = reinterpret_cast( + native->nativeResourceForWindow(QByteArray("xdg_toplevel"), window)); + + const auto seat = reinterpret_cast( + native->nativeResourceForIntegration(QByteArray("wl_seat"))); + + const auto serial = [&]() -> std::optional { + const auto waylandWindow = static_cast( + window->handle()); + if (!waylandWindow) { + return std::nullopt; + } + return waylandWindow->display()->defaultInputDevice()->serial(); + }(); + + if (!toplevel || !seat || !serial) { + return false; + } + + const auto pos = QHighDpi::toNativePixels( + window->mapFromGlobal(QCursor::pos()), + window); + + xdg_toplevel_show_window_menu(toplevel, seat, *serial, pos.x(), pos.y()); + return true; } } // namespace Platform