diff --git a/src/mumble/CMakeLists.txt b/src/mumble/CMakeLists.txt
index 1f3daa534c2..2799c4e4116 100644
--- a/src/mumble/CMakeLists.txt
+++ b/src/mumble/CMakeLists.txt
@@ -230,6 +230,8 @@ set(MUMBLE_SOURCES
"SettingsKeys.h"
"Settings.cpp"
"Settings.h"
+ "SleepInhibitor.cpp"
+ "SleepInhibitor.h"
"SharedMemory.cpp"
"SharedMemory.h"
"SocketRPC.cpp"
diff --git a/src/mumble/LookConfig.cpp b/src/mumble/LookConfig.cpp
index 24032a6df8f..ffeb4c05343 100644
--- a/src/mumble/LookConfig.cpp
+++ b/src/mumble/LookConfig.cpp
@@ -234,6 +234,7 @@ void LookConfig::load(const Settings &r) {
loadCheckBox(qcbEnableDeveloperMenu, r.bEnableDeveloperMenu);
loadCheckBox(qcbLockLayout, (r.wlWindowLayout == Settings::LayoutCustom) && r.bLockLayout);
+ loadCheckBox(qcbInhibitSleep, r.bInhibitSleep);
loadCheckBox(qcbHideTray, r.bHideInTray);
loadCheckBox(qcbStateInTray, r.bStateInTray);
loadCheckBox(qcbShowUserCount, r.bShowUserCount);
@@ -309,6 +310,7 @@ void LookConfig::save() const {
s.quitBehavior = static_cast< QuitBehavior >(qcbQuitBehavior->currentIndex());
s.bEnableDeveloperMenu = qcbEnableDeveloperMenu->isChecked();
s.bLockLayout = qcbLockLayout->isChecked();
+ s.bInhibitSleep = qcbInhibitSleep->isChecked();
s.bHideInTray = qcbHideTray->isChecked();
s.bStateInTray = qcbStateInTray->isChecked();
s.bShowUserCount = qcbShowUserCount->isChecked();
diff --git a/src/mumble/LookConfig.ui b/src/mumble/LookConfig.ui
index 5ddc48e22e3..3ba18ba73ba 100644
--- a/src/mumble/LookConfig.ui
+++ b/src/mumble/LookConfig.ui
@@ -141,6 +141,16 @@
+ -
+
+
+ Prevents the computer from sleeping while connected to a server
+
+
+ Inhibit system sleep while connected
+
+
+
@@ -1288,6 +1298,7 @@
qcbQuitBehavior
qcbEnableDeveloperMenu
qcbLockLayout
+ qcbInhibitSleep
qcbHideTray
qcbStateInTray
qcbSearchUserAction
diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp
index 057005fd85f..a2d4db7d482 100644
--- a/src/mumble/MainWindow.cpp
+++ b/src/mumble/MainWindow.cpp
@@ -43,6 +43,7 @@
#include "ServerHandler.h"
#include "ServerInformation.h"
#include "Settings.h"
+#include "SleepInhibitor.h"
#include "SvgIcon.h"
#include "TalkingUI.h"
#include "TextMessage.h"
@@ -208,6 +209,8 @@ MainWindow::MainWindow(QWidget *p)
QObject::connect(this, &MainWindow::channelStateChanged, this, &MainWindow::on_channelStateChanged);
QAccessible::installFactory(AccessibleSlider::semanticSliderFactory);
+
+ m_sleepInhibitor = new SleepInhibitor(this);
}
// Loading a state that was stored by a different version of Qt can lead to a crash.
@@ -3511,6 +3514,10 @@ void MainWindow::serverConnected() {
MUSuppressAppNap(true);
#endif
+ if (Global::get().s.bInhibitSleep) {
+ m_sleepInhibitor->setInhibit(true);
+ }
+
Global::get().l->clearIgnore();
Global::get().l->setIgnore(Log::UserJoin);
Global::get().l->setIgnore(Log::OtherSelfMute);
@@ -3579,6 +3586,8 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re
MUSuppressAppNap(false);
#endif
+ m_sleepInhibitor->setInhibit(false);
+
QString uname, pw, host;
unsigned short port;
Global::get().sh->getConnectionInfo(host, port, uname, pw);
@@ -4222,6 +4231,10 @@ void MainWindow::openConfigDialog() {
close();
}
}
+
+ if (Global::get().uiSession != 0) {
+ m_sleepInhibitor->setInhibit(Global::get().s.bInhibitSleep);
+ }
}
Global::get().inConfigUI = false;
diff --git a/src/mumble/MainWindow.h b/src/mumble/MainWindow.h
index 462630a48c6..4417060c5b6 100644
--- a/src/mumble/MainWindow.h
+++ b/src/mumble/MainWindow.h
@@ -42,6 +42,7 @@ class UserInformation;
class VoiceRecorderDialog;
class PositionalAudioViewer;
class PTTButtonWidget;
+class SleepInhibitor;
namespace Search {
class SearchDialog;
@@ -206,6 +207,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindow {
std::stack< unsigned int > m_previousChannels;
std::optional< unsigned int > m_movedBackFromChannel;
+ SleepInhibitor *m_sleepInhibitor;
+
static constexpr int stateVersion();
void createActions();
diff --git a/src/mumble/Settings.h b/src/mumble/Settings.h
index 232f987e03e..5d10d4280f3 100644
--- a/src/mumble/Settings.h
+++ b/src/mumble/Settings.h
@@ -432,6 +432,7 @@ struct Settings {
bool bLockLayout = false;
bool bHideInTray = false;
bool bStateInTray = true;
+ bool bInhibitSleep = false;
bool bUsage = true;
bool bShowUserCount = false;
bool bShowVolumeAdjustments = true;
diff --git a/src/mumble/SettingsKeys.h b/src/mumble/SettingsKeys.h
index 6ff85bec573..d554033f989 100644
--- a/src/mumble/SettingsKeys.h
+++ b/src/mumble/SettingsKeys.h
@@ -193,6 +193,7 @@ const SettingsKey OVERLAY_HEADER_STATE = { "overlay_header_state
const SettingsKey SERVER_FILTER_MODE_KEY = { "server_filter_mode" };
const SettingsKey HIDE_IN_TRAY_KEY = { "hide_in_tray" };
const SettingsKey DISPLAY_TALKING_STATE_IN_TRAY_KEY = { "display_talking_state_in_tray" };
+const SettingsKey INHIBIT_SLEEP_KEY = { "inhibit_sleep" };
const SettingsKey SEND_USAGE_STATISTICS_KEY = { "send_usage_statistics" };
const SettingsKey DISPLAY_USER_COUNT_KEY = { "display_user_count" };
const SettingsKey DISPLAY_VOLUME_ADJUSTMENTS_KEY = { "display_volume_adjustments" };
diff --git a/src/mumble/SettingsMacros.h b/src/mumble/SettingsMacros.h
index 293e206cdda..939474c7a4f 100644
--- a/src/mumble/SettingsMacros.h
+++ b/src/mumble/SettingsMacros.h
@@ -152,6 +152,7 @@
PROCESS(ui, USER_DRAG_MODE_KEY, ceUserDrag) \
PROCESS(ui, ALWAYS_ON_TOP_KEY, aotbAlwaysOnTop) \
PROCESS(ui, QUIT_BEHAVIOR_KEY, quitBehavior) \
+ PROCESS(ui, INHIBIT_SLEEP_KEY, bInhibitSleep) \
PROCESS(ui, SHOW_DEVELOPER_MENU_KEY, bEnableDeveloperMenu) \
PROCESS(ui, LOCK_LAYOUT_KEY, bLockLayout) \
PROCESS(ui, MINIMAL_VIEW_KEY, bMinimalView) \
diff --git a/src/mumble/SleepInhibitor.cpp b/src/mumble/SleepInhibitor.cpp
new file mode 100644
index 00000000000..4fc15fa1c1b
--- /dev/null
+++ b/src/mumble/SleepInhibitor.cpp
@@ -0,0 +1,94 @@
+// Copyright The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at .
+
+#include "SleepInhibitor.h"
+
+#if defined(Q_OS_WIN)
+# include
+#elif defined(Q_OS_MAC)
+# include
+#elif defined(USE_DBUS)
+# include
+#endif
+
+SleepInhibitor::SleepInhibitor(QObject *parent) : QObject(parent) {
+}
+
+SleepInhibitor::~SleepInhibitor() {
+ setInhibit(false);
+}
+
+void SleepInhibitor::setInhibit(bool inhibit) {
+ if (inhibit == m_inhibited) {
+ return;
+ }
+
+ if (inhibit) {
+ platformInhibit();
+ } else {
+ platformDeinhibit();
+ }
+
+ m_inhibited = inhibit;
+}
+
+void SleepInhibitor::platformInhibit() {
+#if defined(Q_OS_WIN)
+ SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
+#elif defined(Q_OS_MAC)
+ CFStringRef reasonForActivity = CFStringCreateWithCString(kCFAllocatorDefault, "Mumble is in a call", kCFStringEncodingUTF8);
+ IOReturn success = IOPMAssertionCreateWithDescription(kIOPMAssertionTypeNoDisplaySleep,
+ reasonForActivity,
+ NULL, NULL, NULL, 0, NULL,
+ &m_assertionID);
+ CFRelease(reasonForActivity);
+ if (success != kIOReturnSuccess) {
+ qWarning("SleepInhibitor: Failed to create IOPMAssertion");
+ m_assertionID = 0;
+ }
+#elif defined(USE_DBUS)
+ QDBusInterface screensaver("org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver", QDBusConnection::sessionBus());
+ if (screensaver.isValid()) {
+ QDBusReply reply = screensaver.call("Inhibit", "Mumble", "In a call");
+ if (reply.isValid()) {
+ m_cookie = reply.value();
+ } else {
+ qWarning() << "SleepInhibitor: ScreenSaver Inhibit call failed:" << reply.error().message();
+ }
+ }
+
+ QDBusInterface logind("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus());
+ if (logind.isValid()) {
+ QDBusReply reply = logind.call("Inhibit", "sleep:idle", "Mumble", "In a call", "block");
+ if (reply.isValid()) {
+ m_logindFD = reply.value();
+ } else {
+ qWarning() << "SleepInhibitor: Logind Inhibit call failed:" << reply.error().message();
+ }
+ }
+#endif
+}
+
+void SleepInhibitor::platformDeinhibit() {
+#if defined(Q_OS_WIN)
+ SetThreadExecutionState(ES_CONTINUOUS);
+#elif defined(Q_OS_MAC)
+ if (m_assertionID != 0) {
+ IOPMAssertionRelease(m_assertionID);
+ m_assertionID = 0;
+ }
+#elif defined(USE_DBUS)
+ if (m_cookie != 0) {
+ QDBusInterface screensaver("org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver", QDBusConnection::sessionBus());
+ if (screensaver.isValid()) {
+ screensaver.call("UnInhibit", m_cookie);
+ }
+ m_cookie = 0;
+ }
+ if (m_logindFD.isValid()) {
+ m_logindFD = QDBusUnixFileDescriptor();
+ }
+#endif
+}
diff --git a/src/mumble/SleepInhibitor.h b/src/mumble/SleepInhibitor.h
new file mode 100644
index 00000000000..4fd6f9b9679
--- /dev/null
+++ b/src/mumble/SleepInhibitor.h
@@ -0,0 +1,41 @@
+// Copyright The Mumble Developers. All rights reserved.
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file at the root of the
+// Mumble source tree or at .
+
+#ifndef MUMBLE_MUMBLE_SLEEPINHIBITOR_H_
+#define MUMBLE_MUMBLE_SLEEPINHIBITOR_H_
+
+#include
+
+#include
+#if defined(USE_DBUS)
+# include
+#endif
+
+class SleepInhibitor : public QObject {
+ Q_OBJECT
+ Q_DISABLE_COPY(SleepInhibitor)
+
+public:
+ explicit SleepInhibitor(QObject *parent = nullptr);
+ ~SleepInhibitor() override;
+
+ void setInhibit(bool inhibit);
+
+private:
+ bool m_inhibited = false;
+#if defined(Q_OS_WIN)
+ // No extra state needed for Windows (ES_CONTINUOUS)
+#elif defined(Q_OS_MAC)
+ uint32_t m_assertionID = 0;
+#elif defined(USE_DBUS)
+ uint32_t m_cookie = 0;
+ QDBusUnixFileDescriptor m_logindFD;
+#endif
+
+ void platformInhibit();
+ void platformDeinhibit();
+};
+
+#endif