From 67cbe61879e427a5076576a99f9bbda667b24e1e Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Sun, 7 Mar 2021 08:02:41 +0400 Subject: [PATCH] Check if portal backend is present by absence of errors when getting portal version --- .../platform/linux/linux_gtk_file_dialog.cpp | 5 +- .../platform/linux/linux_xdp_file_dialog.cpp | 67 ++++++++- .../platform/linux/specific_linux.cpp | 130 ------------------ .../platform/linux/specific_linux.h | 2 - snap/snapcraft.yaml | 2 + 5 files changed, 65 insertions(+), 141 deletions(-) diff --git a/Telegram/SourceFiles/platform/linux/linux_gtk_file_dialog.cpp b/Telegram/SourceFiles/platform/linux/linux_gtk_file_dialog.cpp index 320cb3df6..35c46f917 100644 --- a/Telegram/SourceFiles/platform/linux/linux_gtk_file_dialog.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_gtk_file_dialog.cpp @@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/linux/linux_gtk_integration_p.h" #include "platform/linux/linux_gdk_helper.h" #include "platform/linux/linux_desktop_environment.h" -#include "platform/linux/specific_linux.h" #include "lang/lang_keys.h" #include "storage/localstorage.h" #include "base/qt_adapters.h" @@ -641,9 +640,7 @@ bool Supported() { bool Use(Type type) { return qEnvironmentVariableIsSet("TDESKTOP_USE_GTK_FILE_DIALOG") - || DesktopEnvironment::IsGtkBased() - // use as a fallback for portal dialog - || UseXDGDesktopPortal(); + || DesktopEnvironment::IsGtkBased(); } bool Get( diff --git a/Telegram/SourceFiles/platform/linux/linux_xdp_file_dialog.cpp b/Telegram/SourceFiles/platform/linux/linux_xdp_file_dialog.cpp index dfc6a9b72..f8def0cd2 100644 --- a/Telegram/SourceFiles/platform/linux/linux_xdp_file_dialog.cpp +++ b/Telegram/SourceFiles/platform/linux/linux_xdp_file_dialog.cpp @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "platform/linux/linux_xdp_file_dialog.h" #include "platform/platform_file_utilities.h" +#include "platform/linux/linux_desktop_environment.h" #include "platform/linux/specific_linux.h" #include "base/platform/base_platform_info.h" #include "base/platform/linux/base_linux_glibmm_helper.h" @@ -28,6 +29,11 @@ namespace FileDialog { namespace XDP { namespace { +constexpr auto kXDGDesktopPortalService = "org.freedesktop.portal.Desktop"_cs; +constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_cs; +constexpr auto kXDGDesktopPortalFileChooserInterface = "org.freedesktop.portal.FileChooser"_cs; +constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs; + const char *filterRegExp = "^(.*)\\(([a-zA-Z0-9_.,*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$"; @@ -67,6 +73,46 @@ auto MakeFilterList(const QString &filter) { return result; } +std::optional FileChooserPortalVersion() { + try { + const auto connection = Gio::DBus::Connection::get_sync( + Gio::DBus::BusType::BUS_TYPE_SESSION); + + auto reply = connection->call_sync( + std::string(kXDGDesktopPortalObjectPath), + std::string(kPropertiesInterface), + "Get", + base::Platform::MakeGlibVariant(std::tuple{ + Glib::ustring( + std::string(kXDGDesktopPortalFileChooserInterface)), + Glib::ustring("version"), + }), + std::string(kXDGDesktopPortalService)); + + return base::Platform::GlibVariantCast( + base::Platform::GlibVariantCast( + reply.get_child(0))); + } catch (const Glib::Error &e) { + static const auto NotSupportedErrors = { + "org.freedesktop.DBus.Error.Disconnected", + "org.freedesktop.DBus.Error.ServiceUnknown", + }; + + const auto errorName = Gio::DBus::ErrorUtils::get_remote_error(e); + if (ranges::contains(NotSupportedErrors, errorName)) { + return std::nullopt; + } + + LOG(("XDP File Dialog Error: %1").arg( + QString::fromStdString(e.what()))); + } catch (const std::exception &e) { + LOG(("XDP File Dialog Error: %1").arg( + QString::fromStdString(e.what()))); + } + + return std::nullopt; +} + // This is a patched copy of file dialog from qxdgdesktopportal theme plugin. // It allows using XDP file dialog flexibly, // without relying on QT_QPA_PLATFORMTHEME variable. @@ -364,8 +410,8 @@ void XDPFileDialog::openPortal() { _cancellable = Gio::Cancellable::create(); _dbusConnection->call( - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.FileChooser", + std::string(kXDGDesktopPortalObjectPath), + std::string(kXDGDesktopPortalFileChooserInterface), _acceptMode == QFileDialog::AcceptSave ? "SaveFile" : "OpenFile", @@ -387,7 +433,7 @@ void XDPFileDialog::openPortal() { } }, _cancellable, - "org.freedesktop.portal.Desktop"); + std::string(kXDGDesktopPortalService)); } catch (const Glib::Error &e) { LOG(("XDP File Dialog Error: %1").arg( QString::fromStdString(e.what()))); @@ -584,8 +630,19 @@ rpl::producer<> XDPFileDialog::rejected() { } // namespace bool Use(Type type) { - return UseXDGDesktopPortal() - && (type != Type::ReadFolder || CanOpenDirectoryWithPortal()); + static const auto ShouldUse = [&] { + const auto envVar = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL"); + const auto confined = InFlatpak() || InSnap(); + const auto notGtkBased = !DesktopEnvironment::IsGtkBased(); + + return confined || notGtkBased || envVar; + }(); + + static const auto Version = FileChooserPortalVersion(); + + return ShouldUse + && Version.has_value() + && (type != Type::ReadFolder || *Version >= 3); } bool Get( diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.cpp b/Telegram/SourceFiles/platform/linux/specific_linux.cpp index b0887ab02..0aff1da34 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/specific_linux.cpp @@ -72,9 +72,7 @@ constexpr auto kHandlerTypeName = "x-scheme-handler/tg"_cs; constexpr auto kXDGDesktopPortalService = "org.freedesktop.portal.Desktop"_cs; constexpr auto kXDGDesktopPortalObjectPath = "/org/freedesktop/portal/desktop"_cs; -constexpr auto kXDGDesktopPortalKDEService = "org.freedesktop.impl.portal.desktop.kde"_cs; constexpr auto kIBusPortalService = "org.freedesktop.portal.IBus"_cs; -constexpr auto kPropertiesInterface = "org.freedesktop.DBus.Properties"_cs; #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION std::unique_ptr NSWInstance; @@ -201,54 +199,6 @@ PortalAutostart::PortalAutostart(bool start, bool silent) { } } -bool IsXDGDesktopPortalPresent() { - static const auto Result = [&] { - try { - const auto connection = Gio::DBus::Connection::get_sync( - Gio::DBus::BusType::BUS_TYPE_SESSION); - - const auto serviceRegistered = base::Platform::DBus::NameHasOwner( - connection, - std::string(kXDGDesktopPortalService)); - - const auto serviceActivatable = ranges::contains( - base::Platform::DBus::ListActivatableNames(connection), - Glib::ustring(std::string(kXDGDesktopPortalService))); - - return serviceRegistered || serviceActivatable; - } catch (...) { - } - - return false; - }(); - - return Result; -} - -bool IsXDGDesktopPortalKDEPresent() { - static const auto Result = [&] { - try { - const auto connection = Gio::DBus::Connection::get_sync( - Gio::DBus::BusType::BUS_TYPE_SESSION); - - const auto serviceRegistered = base::Platform::DBus::NameHasOwner( - connection, - std::string(kXDGDesktopPortalKDEService)); - - const auto serviceActivatable = ranges::contains( - base::Platform::DBus::ListActivatableNames(connection), - Glib::ustring(std::string(kXDGDesktopPortalKDEService))); - - return serviceRegistered || serviceActivatable; - } catch (...) { - } - - return false; - }(); - - return Result; -} - bool IsIBusPortalPresent() { static const auto Result = [&] { try { @@ -272,39 +222,6 @@ bool IsIBusPortalPresent() { return Result; } - -uint FileChooserPortalVersion() { - static const auto Result = [&]() -> uint { - try { - const auto connection = Gio::DBus::Connection::get_sync( - Gio::DBus::BusType::BUS_TYPE_SESSION); - - auto reply = connection->call_sync( - std::string(kXDGDesktopPortalObjectPath), - std::string(kPropertiesInterface), - "Get", - base::Platform::MakeGlibVariant(std::tuple{ - Glib::ustring("org.freedesktop.portal.FileChooser"), - Glib::ustring("version"), - }), - std::string(kXDGDesktopPortalService)); - - return base::Platform::GlibVariantCast( - base::Platform::GlibVariantCast( - reply.get_child(0))); - } catch (const Glib::Error &e) { - LOG(("Error getting FileChooser portal version: %1") - .arg(QString::fromStdString(e.what()))); - } catch (const std::exception &e) { - LOG(("Error getting FileChooser portal version: %1") - .arg(QString::fromStdString(e.what()))); - } - - return 0; - }(); - - return Result; -} #endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION QByteArray EscapeShell(const QByteArray &content) { @@ -486,40 +403,6 @@ bool AreQtPluginsBundled() { #endif // DESKTOP_APP_USE_PACKAGED && !DESKTOP_APP_USE_PACKAGED_LAZY } -bool UseXDGDesktopPortal() { -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - static const auto Result = [&] { - if (InFlatpak() || InSnap()) { - return true; - } - - const auto envVar = qEnvironmentVariableIsSet("TDESKTOP_USE_PORTAL"); - const auto portalPresent = IsXDGDesktopPortalPresent(); - const auto neededForKde = DesktopEnvironment::IsKDE() - && IsXDGDesktopPortalKDEPresent(); - - return portalPresent - && (neededForKde || envVar); - }(); - - return Result; -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - - return false; -} - -bool CanOpenDirectoryWithPortal() { -#ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - static const auto Result = [&] { - return FileChooserPortalVersion() >= 3; - }(); - - return Result; -#endif // !DESKTOP_APP_DISABLE_DBUS_INTEGRATION - - return false; -} - QString AppRuntimeDirectory() { static const auto Result = [&] { auto runtimeDir = QStandardPaths::writableLocation( @@ -792,19 +675,6 @@ void start() { #endif // DESKTOP_APP_USE_PACKAGED_FONTS #ifndef DESKTOP_APP_DISABLE_DBUS_INTEGRATION - // Tell the user when XDP file dialog is used - DEBUG_LOG(("Checking for XDG Desktop Portal...")); - if (IsXDGDesktopPortalPresent()) { - DEBUG_LOG(("XDG Desktop Portal is present!")); - if (UseXDGDesktopPortal()) { - LOG(("Using XDG Desktop Portal.")); - } else { - DEBUG_LOG(("Not using XDG Desktop Portal.")); - } - } else { - DEBUG_LOG(("XDG Desktop Portal is not present :(")); - } - // IBus has changed its socket path several times // and each change should be synchronized with Qt. // Moreover, the last time Qt changed the path, diff --git a/Telegram/SourceFiles/platform/linux/specific_linux.h b/Telegram/SourceFiles/platform/linux/specific_linux.h index 38e1b4c33..0f84f0919 100644 --- a/Telegram/SourceFiles/platform/linux/specific_linux.h +++ b/Telegram/SourceFiles/platform/linux/specific_linux.h @@ -18,8 +18,6 @@ namespace Platform { bool InFlatpak(); bool InSnap(); bool AreQtPluginsBundled(); -bool UseXDGDesktopPortal(); -bool CanOpenDirectoryWithPortal(); QString AppRuntimeDirectory(); QString GetLauncherBasename(); diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index cd4a4d385..85deb8712 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -404,6 +404,8 @@ parts: - -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/bin - -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/mkspecs - -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/examples + # Allow tdesktop's custom try-portal-and-fallback logic to work + - -./usr/lib/$SNAPCRAFT_ARCH_TRIPLET/qt5/plugins/platformthemes - -./usr/lib/qt5 - -./usr/share after: