// Copyright 2024 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "UICommon/DBusUtils.h" #include #include #include #include #include #include #include "Common/Logging/Log.h" namespace DBusUtils { static bool InhibitFDO(); static bool InhibitXfce(); static bool InhibitMate(); static bool InhibitPortal(); static void Uninhibit(); static constexpr char s_app_id[] = "org.DolphinEmu.dolphin-emu"; // Cookie for the org.freedesktop.ScreenSaver interface static uint32_t s_fdo_cookie = 0; // Cookie for the org.xfce.ScreenSaver interface static uint32_t s_xfce_cookie = 0; // Cookie for the org.mate.ScreenSaver interface static uint32_t s_mate_cookie = 0; // Return handle for the org.freedesktop.portal.Desktop interface static QString s_portal_handle; // Uses D-Bus to inhibit the screensaver // Tries various D-Bus interfaces until it finds one that works void InhibitScreenSaver(bool inhibit) { if (inhibit) { if (s_fdo_cookie || s_xfce_cookie || s_mate_cookie || !s_portal_handle.isEmpty()) return; if (!InhibitFDO() && !InhibitXfce() && !InhibitMate() && !InhibitPortal()) INFO_LOG_FMT(VIDEO, "Could not inhibit screensaver: No services available"); } else Uninhibit(); } // Inhibits screensaver on Xfce desktop static bool InhibitXfce() { QDBusInterface interface("org.xfce.ScreenSaver", "/", "org.xfce.ScreenSaver"); if (!interface.isValid()) return false; QDBusReply reply = interface.call("Inhibit", s_app_id, QObject::tr("Playing a game")); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.xfce.ScreenSaver::Inhibit failed: {}", interface.lastError().message().toStdString()); return false; } INFO_LOG_FMT(VIDEO, "org.xfce.ScreenSaver::Inhibit succeeded"); s_xfce_cookie = reply; return true; } // Inhibits screensaver on the MATE desktop // MATE advertises support for xdg-desktop-portal Inhibit, // but it doesn't work as of Fedora 40 static bool InhibitMate() { QDBusInterface interface("org.mate.ScreenSaver", "/org/mate/ScreenSaver", "org.mate.ScreenSaver"); if (!interface.isValid()) return false; QDBusReply reply = interface.call("Inhibit", s_app_id, QObject::tr("Playing a game")); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.mate.ScreenSaver::Inhibit failed: {}", interface.lastError().message().toStdString()); return false; } INFO_LOG_FMT(VIDEO, "org.mate.ScreenSaver::Inhibit succeeded"); s_mate_cookie = reply; return true; } // Inhibits screensaver on GNOME, KDE and Cinnamon static bool InhibitFDO() { QDBusInterface interface("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver"); if (!interface.isValid()) return false; QDBusReply reply = interface.call("Inhibit", s_app_id, QObject::tr("Playing a game")); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.freedesktop.ScreenSaver::Inhibit failed: {}", interface.lastError().message().toStdString()); return false; } INFO_LOG_FMT(VIDEO, "org.freedesktop.ScreenSaver::Inhibit succeeded"); s_fdo_cookie = reply; return true; } // Inhibits screensaver when sandboxed through Flatpak // Does not work on KDE Plasma versions before 6.1.5 static bool InhibitPortal() { QDBusInterface interface("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", "org.freedesktop.portal.Inhibit"); if (!interface.isValid()) return false; QHash options; options["handle_token"] = "dolphin_" + QString::number(std::rand(), 0x10); options["reason"] = QObject::tr("Playing a game"); uint32_t flags = 9; // logout | idle QDBusReply reply = interface.call("Inhibit", "", flags, options); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.freedesktop.portal.Desktop::Inhibit failed: {}", interface.lastError().message().toStdString()); return false; } INFO_LOG_FMT(VIDEO, "org.freedesktop.portal.Desktop::Inhibit succeeded"); s_portal_handle = reply.value().path(); return true; } static void Uninhibit() { if (s_fdo_cookie) { QDBusInterface interface("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver"); interface.call("UnInhibit", s_fdo_cookie); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.freedesktop.ScreenSaver::UnInhibit failed: {}", interface.lastError().message().toStdString()); } else { INFO_LOG_FMT(VIDEO, "org.freedesktop.ScreenSaver::UnInhibit succeeded"); } s_fdo_cookie = 0; } if (s_xfce_cookie) { QDBusInterface interface("org.xfce.ScreenSaver", "/org/xfce/ScreenSaver", "org.xfce.ScreenSaver"); interface.call("UnInhibit", s_xfce_cookie); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.xfce.ScreenSaver::UnInhibit failed: {}", interface.lastError().message().toStdString()); } else { INFO_LOG_FMT(VIDEO, "org.xfce.ScreenSaver::UnInhibit succeeded"); } s_xfce_cookie = 0; } if (s_mate_cookie) { QDBusInterface interface("org.mate.ScreenSaver", "/", "org.mate.ScreenSaver"); interface.call("UnInhibit", s_mate_cookie); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.mate.ScreenSaver::UnInhibit failed: {}", interface.lastError().message().toStdString()); } else { INFO_LOG_FMT(VIDEO, "org.mate.ScreenSaver::UnInhibit succeeded"); } s_mate_cookie = 0; } if (!s_portal_handle.isEmpty()) { QDBusInterface interface("org.freedesktop.portal.Desktop", s_portal_handle, "org.freedesktop.portal.Request"); interface.call("Close"); if (interface.lastError().isValid()) { WARN_LOG_FMT(VIDEO, "org.freedesktop.portal.Request::Close failed: {}", interface.lastError().message().toStdString()); } else { INFO_LOG_FMT(VIDEO, "org.freedesktop.portal.Request::Close succeeded"); } s_portal_handle = QString(); } } } // namespace DBusUtils