diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f5f7d4b1..1511b9778 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -211,6 +211,10 @@ if (ENABLE_QT) find_package(Qt5 REQUIRED COMPONENTS Widgets Multimedia Concurrent ${QT_PREFIX_HINT}) + if (UNIX AND NOT APPLE) + find_package(Qt5 REQUIRED COMPONENTS DBus ${QT_PREFIX_HINT}) + endif() + if (ENABLE_QT_TRANSLATION) find_package(Qt5 REQUIRED COMPONENTS LinguistTools ${QT_PREFIX_HINT}) endif() diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 4634c9603..07be722c5 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -269,6 +269,10 @@ target_link_libraries(citra-qt PRIVATE audio_core common core input_common netwo target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia Qt5::Concurrent) target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) +if (UNIX AND NOT APPLE) + target_link_libraries(citra-qt PRIVATE Qt5::DBus) +endif() + target_compile_definitions(citra-qt PRIVATE # Use QStringBuilder for string concatenation to reduce # the overall number of temporary strings created. diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 2905130e0..4f7b30a84 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -24,6 +24,11 @@ #ifdef _WIN32 #include #endif +#ifdef __unix__ +#include +#include +#include +#endif #include "citra_qt/aboutdialog.h" #include "citra_qt/applets/mii_selector.h" #include "citra_qt/applets/swkbd.h" @@ -945,16 +950,72 @@ void GMainWindow::OnOpenUpdater() { updater->LaunchUI(); } +#if defined(__unix__) && !defined(__APPLE__) +static std::optional HoldWakeLockLinux(u32 window_id = 0) { + if (!QDBusConnection::sessionBus().isConnected()) { + return {}; + } + // reference: https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Inhibit + QDBusInterface xdp(QStringLiteral("org.freedesktop.portal.Desktop"), + QStringLiteral("/org/freedesktop/portal/desktop"), + QStringLiteral("org.freedesktop.portal.Inhibit")); + if (!xdp.isValid()) { + LOG_WARNING(Frontend, "Couldn't connect to XDP D-Bus endpoint"); + return {}; + } + QVariantMap options = {}; + //: TRANSLATORS: This string is shown to the user to explain why Citra needs to prevent the + //: computer from sleeping + options.insert(QString::fromLatin1("reason"), + QCoreApplication::translate("GMainWindow", "Citra is running a game")); + // 0x4: Suspend lock; 0x8: Idle lock + QDBusReply reply = + xdp.call(QString::fromLatin1("Inhibit"), + QString::fromLatin1("x11:") + QString::number(window_id, 16), 12U, options); + + if (reply.isValid()) { + return reply.value(); + } + LOG_WARNING(Frontend, "Couldn't read Inhibit reply from XDP: {}", + reply.error().message().toStdString()); + return {}; +} + +static void ReleaseWakeLockLinux(const QDBusObjectPath& lock) { + if (!QDBusConnection::sessionBus().isConnected()) { + return; + } + QDBusInterface unlocker(QString::fromLatin1("org.freedesktop.portal.Desktop"), lock.path(), + QString::fromLatin1("org.freedesktop.portal.Request")); + unlocker.call(QString::fromLatin1("Close")); +} +#endif // __unix__ + void GMainWindow::PreventOSSleep() { #ifdef _WIN32 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); -#endif +#elif defined(HAVE_SDL2) + SDL_DisableScreenSaver(); +#ifdef __unix__ + auto reply = HoldWakeLockLinux(winId()); + if (reply) { + wake_lock = std::move(reply.value()); + } +#endif // __unix__ +#endif // _WIN32 } void GMainWindow::AllowOSSleep() { #ifdef _WIN32 SetThreadExecutionState(ES_CONTINUOUS); -#endif +#elif defined(HAVE_SDL2) + SDL_EnableScreenSaver(); +#ifdef __unix__ + if (!wake_lock.path().isEmpty()) { + ReleaseWakeLockLinux(wake_lock); + } +#endif // __unix__ +#endif // _WIN32 } bool GMainWindow::LoadROM(const QString& filename) { diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 85dd95587..c323072d6 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -16,6 +16,10 @@ #include "core/hle/service/am/am.h" #include "core/savestate.h" +#ifdef __unix__ +#include +#endif + class AboutDialog; class Config; class ClickableLabel; @@ -329,6 +333,10 @@ private: HotkeyRegistry hotkey_registry; +#ifdef __unix__ + QDBusObjectPath wake_lock{}; +#endif + protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override;