diff --git a/Source/Core/DolphinNoGUI/PlatformX11.cpp b/Source/Core/DolphinNoGUI/PlatformX11.cpp index 94a72b4c53..8fed2c8c87 100644 --- a/Source/Core/DolphinNoGUI/PlatformX11.cpp +++ b/Source/Core/DolphinNoGUI/PlatformX11.cpp @@ -26,6 +26,7 @@ static constexpr auto X_None = None; #include #include #include +#include "UICommon/UICommon.h" #include "UICommon/X11Utils.h" #include "VideoCommon/Present.h" @@ -110,7 +111,7 @@ bool PlatformX11::Init() ProcessEvents(); if (Config::Get(Config::MAIN_DISABLE_SCREENSAVER)) - X11Utils::InhibitScreensaver(m_window, true); + UICommon::InhibitScreenSaver(true); #ifdef HAVE_XRANDR m_xrr_config = new X11Utils::XRRConfiguration(m_display, m_window); diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 5c3ca31d5a..3f977b82b6 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1686,12 +1686,7 @@ void MainWindow::UpdateScreenSaverInhibition() m_is_screensaver_inhibited = inhibit; -#ifdef HAVE_X11 - if (GetWindowSystemType() == WindowSystemType::X11) - UICommon::InhibitScreenSaver(winId(), inhibit); -#else UICommon::InhibitScreenSaver(inhibit); -#endif } bool MainWindow::eventFilter(QObject* object, QEvent* event) diff --git a/Source/Core/UICommon/CMakeLists.txt b/Source/Core/UICommon/CMakeLists.txt index 67460ac1af..fa247514e8 100644 --- a/Source/Core/UICommon/CMakeLists.txt +++ b/Source/Core/UICommon/CMakeLists.txt @@ -43,6 +43,13 @@ if ((DEFINED CMAKE_ANDROID_ARCH_ABI AND CMAKE_ANDROID_ARCH_ABI MATCHES "x86|x86_ target_link_libraries(uicommon PRIVATE bdisasm) endif() +if(UNIX AND NOT APPLE AND NOT ANDROID AND ENABLE_QT) + find_package(Qt6 REQUIRED COMPONENTS DBus) + target_sources(uicommon PRIVATE DBusUtils.cpp) + target_compile_definitions(uicommon PRIVATE -DHAVE_QTDBUS=1) + target_link_libraries(uicommon PUBLIC Qt6::DBus) +endif() + if(X11_FOUND) target_sources(uicommon PRIVATE X11Utils.cpp) target_link_libraries(uicommon PUBLIC PkgConfig::XRANDR PkgConfig::X11) diff --git a/Source/Core/UICommon/DBusUtils.cpp b/Source/Core/UICommon/DBusUtils.cpp new file mode 100644 index 0000000000..6f92f662c5 --- /dev/null +++ b/Source/Core/UICommon/DBusUtils.cpp @@ -0,0 +1,204 @@ +// 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 diff --git a/Source/Core/UICommon/DBusUtils.h b/Source/Core/UICommon/DBusUtils.h new file mode 100644 index 0000000000..5353efc319 --- /dev/null +++ b/Source/Core/UICommon/DBusUtils.h @@ -0,0 +1,11 @@ +// Copyright 2024 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace DBusUtils +{ + +void InhibitScreenSaver(bool inhibit); + +} // namespace DBusUtils diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index d0f8345852..6fa05ef807 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -50,8 +50,8 @@ #include "UICommon/DiscordPresence.h" #include "UICommon/USBUtils.h" -#ifdef HAVE_X11 -#include "UICommon/X11Utils.h" +#ifdef HAVE_QTDBUS +#include "UICommon/DBusUtils.h" #endif #ifdef __APPLE__ @@ -480,17 +480,13 @@ bool TriggerSTMPowerEvent() return true; } -#ifdef HAVE_X11 -void InhibitScreenSaver(Window win, bool inhibit) -#else void InhibitScreenSaver(bool inhibit) -#endif { // Inhibit the screensaver. Depending on the operating system this may also // disable low-power states and/or screen dimming. -#ifdef HAVE_X11 - X11Utils::InhibitScreensaver(win, inhibit); +#ifdef HAVE_QTDBUS + DBusUtils::InhibitScreenSaver(inhibit); #endif #ifdef _WIN32 diff --git a/Source/Core/UICommon/UICommon.h b/Source/Core/UICommon/UICommon.h index f57518cf14..f23a0005c7 100644 --- a/Source/Core/UICommon/UICommon.h +++ b/Source/Core/UICommon/UICommon.h @@ -17,11 +17,7 @@ void Shutdown(); void InitControllers(const WindowSystemInfo& wsi); void ShutdownControllers(); -#ifdef HAVE_X11 -void InhibitScreenSaver(unsigned long win, bool enable); -#else -void InhibitScreenSaver(bool enable); -#endif +void InhibitScreenSaver(bool inhibit); // Calls std::locale::global, selecting a fallback locale if the // requested locale isn't available diff --git a/Source/Core/UICommon/X11Utils.cpp b/Source/Core/UICommon/X11Utils.cpp index 659017ad53..219c897d9e 100644 --- a/Source/Core/UICommon/X11Utils.cpp +++ b/Source/Core/UICommon/X11Utils.cpp @@ -45,24 +45,6 @@ bool ToggleFullscreen(Display* dpy, Window win) return true; } -void InhibitScreensaver(Window win, bool suspend) -{ - char id[11]; - snprintf(id, sizeof(id), "0x%lx", win); - - // Call xdg-screensaver - char* argv[4] = {(char*)"xdg-screensaver", (char*)(suspend ? "suspend" : "resume"), id, nullptr}; - pid_t pid; - if (!posix_spawnp(&pid, "xdg-screensaver", nullptr, nullptr, argv, environ)) - { - int status; - while (waitpid(pid, &status, 0) == -1) - ; - - INFO_LOG_FMT(VIDEO, "Started xdg-screensaver (PID = {})", pid); - } -} - #ifdef HAVE_XRANDR XRRConfiguration::XRRConfiguration(Display* _dpy, Window _win) : dpy(_dpy), win(_win), screenResources(nullptr), outputInfo(nullptr), crtcInfo(nullptr), diff --git a/Source/Core/UICommon/X11Utils.h b/Source/Core/UICommon/X11Utils.h index 7a406bd641..e71fada4c3 100644 --- a/Source/Core/UICommon/X11Utils.h +++ b/Source/Core/UICommon/X11Utils.h @@ -20,10 +20,6 @@ namespace X11Utils { bool ToggleFullscreen(Display* dpy, Window win); -Window XWindowFromHandle(void* Handle); -Display* XDisplayFromHandle(void* Handle); - -void InhibitScreensaver(Window win, bool suspend); #ifdef HAVE_XRANDR class XRRConfiguration