Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux: Use D-Bus to inhibit screensaver #13076

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Source/Core/DolphinNoGUI/PlatformX11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ static constexpr auto X_None = None;
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "UICommon/UICommon.h"
#include "UICommon/X11Utils.h"
#include "VideoCommon/Present.h"

Expand Down Expand Up @@ -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);
Expand Down
5 changes: 0 additions & 5 deletions Source/Core/DolphinQt/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions Source/Core/UICommon/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
204 changes: 204 additions & 0 deletions Source/Core/UICommon/DBusUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// Copyright 2024 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "UICommon/DBusUtils.h"

#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
#include <QHash>
#include <QObject>
#include <QString>

#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<uint32_t> 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<uint32_t> 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<uint32_t> 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<QString, QVariant> options;
options["handle_token"] = "dolphin_" + QString::number(std::rand(), 0x10);
options["reason"] = QObject::tr("Playing a game");
uint32_t flags = 9; // logout | idle
QDBusReply<QDBusObjectPath> 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
11 changes: 11 additions & 0 deletions Source/Core/UICommon/DBusUtils.h
Original file line number Diff line number Diff line change
@@ -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
12 changes: 4 additions & 8 deletions Source/Core/UICommon/UICommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down Expand Up @@ -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
Expand Down
6 changes: 1 addition & 5 deletions Source/Core/UICommon/UICommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 0 additions & 18 deletions Source/Core/UICommon/X11Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
4 changes: 0 additions & 4 deletions Source/Core/UICommon/X11Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down