/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "platform/linux/linux_wayland_integration.h" #include "base/platform/linux/base_linux_wayland_utilities.h" #include "base/qt_signal_producer.h" #include "base/flat_map.h" #include #include #include #include #include #include using QWlApp = QNativeInterface::QWaylandApplication; using namespace QNativeInterface::Private; using namespace base::Platform::Wayland; namespace Platform { namespace internal { namespace { class PlasmaShell : public Global { public: using Global::Global; using Surface = AutoDestroyer; base::flat_map surfaces; }; } // namespace struct WaylandIntegration::Private : public AutoDestroyer { Private(not_null native) : AutoDestroyer(wl_display_get_registry(native->display())) , display(native->display()) { wl_display_roundtrip(display); } QtWayland::org_kde_plasma_surface plasmaSurface(QWindow *window); const not_null display; std::optional plasmaShell; protected: void registry_global( uint32_t name, const QString &interface, uint32_t version) override { if (interface == qstr("org_kde_plasma_shell")) { plasmaShell.emplace(object(), name, version); } } void registry_global_remove(uint32_t name) override { if (plasmaShell && name == plasmaShell->id()) { plasmaShell = std::nullopt; } } }; QtWayland::org_kde_plasma_surface WaylandIntegration::Private::plasmaSurface( QWindow *window) { if (!plasmaShell) { return {}; } const auto native = window->nativeInterface(); if (!native) { return {}; } const auto surface = native->surface(); if (!surface) { return {}; } const auto it = plasmaShell->surfaces.find(surface); if (it != plasmaShell->surfaces.cend()) { return it->second; } const auto plasmaSurface = plasmaShell->get_surface(surface); if (!plasmaSurface) { return {}; } const auto result = plasmaShell->surfaces.emplace(surface, plasmaSurface); base::qt_signal_producer( native, &QWaylandWindow::surfaceDestroyed ) | rpl::start_with_next([=] { auto it = plasmaShell->surfaces.find(surface); if (it != plasmaShell->surfaces.cend()) { plasmaShell->surfaces.erase(it); } }, result.first->second.lifetime()); return result.first->second; } WaylandIntegration::WaylandIntegration() : _private(std::make_unique(qApp->nativeInterface())) { } WaylandIntegration::~WaylandIntegration() = default; WaylandIntegration *WaylandIntegration::Instance() { const auto native = qApp->nativeInterface(); if (!native) return nullptr; static std::optional instance; if (instance && native->display() != instance->_private->display) { instance.reset(); } if (!instance) { instance.emplace(); base::qt_signal_producer( QGuiApplication::platformNativeInterface(), &QObject::destroyed ) | rpl::start_with_next([] { instance = std::nullopt; }, instance->_private->lifetime()); } return &*instance; } bool WaylandIntegration::skipTaskbarSupported() { return _private->plasmaShell.has_value(); } void WaylandIntegration::skipTaskbar(QWindow *window, bool skip) { auto plasmaSurface = _private->plasmaSurface(window); if (!plasmaSurface.isInitialized()) { return; } plasmaSurface.set_skip_taskbar(skip); } } // namespace internal } // namespace Platform