Add reboot option when downloads complete

This commit implements a new "Reboot System" option that allows users to automatically reboot the computer when all downloads are complete, similar to the existing shutdown, suspend, and hibernate options.

Closes #10774.
PR #23525.
This commit is contained in:
Vasiliy Kostin
2025-11-30 14:16:48 +03:00
committed by GitHub
parent 8b9064a33c
commit f2f4676824
9 changed files with 90 additions and 16 deletions

View File

@@ -776,8 +776,9 @@ void Application::allTorrentsFinished()
bool isShutdown = pref->shutdownWhenDownloadsComplete();
bool isSuspend = pref->suspendWhenDownloadsComplete();
bool isHibernate = pref->hibernateWhenDownloadsComplete();
bool isReboot = pref->rebootWhenDownloadsComplete();
bool haveAction = isExit || isShutdown || isSuspend || isHibernate;
const bool haveAction = isExit || isShutdown || isSuspend || isHibernate || isReboot;
if (!haveAction) return;
ShutdownDialogAction action = ShutdownDialogAction::Exit;
@@ -787,6 +788,8 @@ void Application::allTorrentsFinished()
action = ShutdownDialogAction::Hibernate;
else if (isShutdown)
action = ShutdownDialogAction::Shutdown;
else if (isReboot)
action = ShutdownDialogAction::Reboot;
#ifndef DISABLE_GUI
// ask confirm
@@ -808,6 +811,7 @@ void Application::allTorrentsFinished()
pref->setShutdownWhenDownloadsComplete(false);
pref->setSuspendWhenDownloadsComplete(false);
pref->setHibernateWhenDownloadsComplete(false);
pref->setRebootWhenDownloadsComplete(false);
// Make sure preferences are synced before exiting
m_shutdownAct = action;
}

View File

@@ -1297,6 +1297,19 @@ void Preferences::setShutdownWhenDownloadsComplete(const bool shutdown)
setValue(u"Preferences/Downloads/AutoShutDownOnCompletion"_s, shutdown);
}
bool Preferences::rebootWhenDownloadsComplete() const
{
return value(u"Preferences/Downloads/AutoRebootOnCompletion"_s, false);
}
void Preferences::setRebootWhenDownloadsComplete(const bool reboot)
{
if (reboot == rebootWhenDownloadsComplete())
return;
setValue(u"Preferences/Downloads/AutoRebootOnCompletion"_s, reboot);
}
bool Preferences::suspendWhenDownloadsComplete() const
{
return value(u"Preferences/Downloads/AutoSuspendOnCompletion"_s, false);

View File

@@ -287,6 +287,8 @@ public:
bool shutdownWhenDownloadsComplete() const;
void setShutdownWhenDownloadsComplete(bool shutdown);
bool rebootWhenDownloadsComplete() const;
void setRebootWhenDownloadsComplete(bool reboot);
bool suspendWhenDownloadsComplete() const;
void setSuspendWhenDownloadsComplete(bool suspend);
bool hibernateWhenDownloadsComplete() const;

View File

@@ -37,7 +37,8 @@ enum class ShutdownDialogAction
Exit,
Shutdown,
Suspend,
Hibernate
Hibernate,
Reboot
};
using QStringMap = QMap<QString, QString>;

View File

@@ -87,22 +87,30 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
{
::SetSuspendState(TRUE, FALSE, FALSE);
}
else
else if (action == ShutdownDialogAction::Shutdown)
{
std::wstring msg = QCoreApplication::translate("misc"
, "qBittorrent will shutdown the computer now because all downloads are complete.").toStdWString();
::InitiateSystemShutdownW(nullptr, msg.data(), 10, TRUE, FALSE);
}
else if (action == ShutdownDialogAction::Reboot)
{
std::wstring msg = QCoreApplication::translate("misc"
, "qBittorrent will reboot the computer now because all downloads are complete.").toStdWString();
::InitiateSystemShutdownW(nullptr, msg.data(), 10, TRUE, TRUE);
}
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0);
#elif defined(Q_OS_MACOS)
AEEventID EventToSend;
if (action != ShutdownDialogAction::Shutdown)
AEEventID EventToSend {};
if (action == ShutdownDialogAction::Suspend)
EventToSend = kAESleep;
else
else if (action == ShutdownDialogAction::Reboot)
EventToSend = kAERestart;
else if (action == ShutdownDialogAction::Shutdown)
EventToSend = kAEShutDown;
AEAddressDesc targetDesc;
const ProcessSerialNumber kPSNOfSystemProcess = {0, kSystemProcess};
@@ -133,7 +141,7 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
#elif defined(QBT_USES_DBUS)
// Use dbus to power off / suspend the system
if (action != ShutdownDialogAction::Shutdown)
if ((action == ShutdownDialogAction::Suspend) || (action == ShutdownDialogAction::Hibernate))
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface(u"org.freedesktop.login1"_s, u"/org/freedesktop/login1"_s,
@@ -166,7 +174,7 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
else
halIface.call(u"Hibernate"_s);
}
else
else if (action == ShutdownDialogAction::Shutdown)
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface(u"org.freedesktop.login1"_s, u"/org/freedesktop/login1"_s,
@@ -190,6 +198,30 @@ void Utils::OS::shutdownComputer([[maybe_unused]] const ShutdownDialogAction &ac
QDBusConnection::systemBus());
halIface.call(u"Shutdown"_s);
}
else if (action == ShutdownDialogAction::Reboot)
{
// Some recent systems use systemd's logind
QDBusInterface login1Iface(u"org.freedesktop.login1"_s, u"/org/freedesktop/login1"_s,
u"org.freedesktop.login1.Manager"_s, QDBusConnection::systemBus());
if (login1Iface.isValid())
{
login1Iface.call(u"Reboot"_s, false);
return;
}
// Else, other recent systems use ConsoleKit
QDBusInterface consolekitIface(u"org.freedesktop.ConsoleKit"_s, u"/org/freedesktop/ConsoleKit/Manager"_s,
u"org.freedesktop.ConsoleKit.Manager"_s, QDBusConnection::systemBus());
if (consolekitIface.isValid())
{
consolekitIface.call(u"Restart"_s);
return;
}
// HAL (older systems)
QDBusInterface halIface(u"org.freedesktop.Hal"_s, u"/org/freedesktop/Hal/devices/computer"_s,
u"org.freedesktop.Hal.Device.SystemPowerManagement"_s,
QDBusConnection::systemBus());
halIface.call(u"Reboot"_s);
}
#endif
}

View File

@@ -388,10 +388,16 @@ MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, con
autoShutdownGroup->addAction(m_ui->actionAutoShutdown);
autoShutdownGroup->addAction(m_ui->actionAutoSuspend);
autoShutdownGroup->addAction(m_ui->actionAutoHibernate);
autoShutdownGroup->addAction(m_ui->actionAutoReboot);
#if (!defined(Q_OS_UNIX) || defined(Q_OS_MACOS)) || defined(QBT_USES_DBUS)
m_ui->actionAutoShutdown->setChecked(pref->shutdownWhenDownloadsComplete());
m_ui->actionAutoReboot->setChecked(pref->rebootWhenDownloadsComplete());
m_ui->actionAutoSuspend->setChecked(pref->suspendWhenDownloadsComplete());
m_ui->actionAutoHibernate->setChecked(pref->hibernateWhenDownloadsComplete());
#ifdef Q_OS_MACOS
// macOS doesn't support Hibernate via Apple Events API
m_ui->actionAutoHibernate->setDisabled(true);
#endif
#else
m_ui->actionAutoShutdown->setDisabled(true);
m_ui->actionAutoSuspend->setDisabled(true);
@@ -1790,30 +1796,31 @@ void MainWindow::on_actionCriticalMessages_triggered(const bool checked)
setExecutionLogMsgTypes(flags);
}
void MainWindow::on_actionAutoExit_toggled(bool enabled)
void MainWindow::on_actionAutoExit_toggled(const bool enabled)
{
qDebug() << Q_FUNC_INFO << enabled;
Preferences::instance()->setShutdownqBTWhenDownloadsComplete(enabled);
}
void MainWindow::on_actionAutoSuspend_toggled(bool enabled)
void MainWindow::on_actionAutoSuspend_toggled(const bool enabled)
{
qDebug() << Q_FUNC_INFO << enabled;
Preferences::instance()->setSuspendWhenDownloadsComplete(enabled);
}
void MainWindow::on_actionAutoHibernate_toggled(bool enabled)
void MainWindow::on_actionAutoHibernate_toggled(const bool enabled)
{
qDebug() << Q_FUNC_INFO << enabled;
Preferences::instance()->setHibernateWhenDownloadsComplete(enabled);
}
void MainWindow::on_actionAutoShutdown_toggled(bool enabled)
void MainWindow::on_actionAutoShutdown_toggled(const bool enabled)
{
qDebug() << Q_FUNC_INFO << enabled;
Preferences::instance()->setShutdownWhenDownloadsComplete(enabled);
}
void MainWindow::on_actionAutoReboot_toggled(const bool enabled)
{
Preferences::instance()->setRebootWhenDownloadsComplete(enabled);
}
void MainWindow::updatePowerManagementState() const
{
const auto *pref = Preferences::instance();

View File

@@ -158,6 +158,7 @@ private slots:
void on_actionAutoSuspend_toggled(bool);
void on_actionAutoHibernate_toggled(bool);
void on_actionAutoShutdown_toggled(bool);
void on_actionAutoReboot_toggled(bool);
void on_actionAbout_triggered();
void on_actionStatistics_triggered();
void on_actionCreateTorrent_triggered();

View File

@@ -76,6 +76,7 @@
<addaction name="actionAutoExit"/>
<addaction name="actionAutoSuspend"/>
<addaction name="actionAutoHibernate"/>
<addaction name="actionAutoReboot"/>
<addaction name="actionAutoShutdown"/>
</widget>
<addaction name="actionCreateTorrent"/>
@@ -397,6 +398,14 @@
<string>Sh&amp;utdown System</string>
</property>
</action>
<action name="actionAutoReboot">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Reboot System</string>
</property>
</action>
<action name="actionAutoShutdownDisabled">
<property name="checkable">
<bool>true</bool>

View File

@@ -134,6 +134,11 @@ void ShutdownConfirmDialog::initText()
okButton->setText(tr("&Hibernate Now"));
setWindowTitle(tr("Hibernate confirmation"));
break;
case ShutdownDialogAction::Reboot:
m_msg = tr("The computer is going to reboot.");
okButton->setText(tr("&Reboot Now"));
setWindowTitle(tr("Reboot confirmation"));
break;
}
m_msg += u'\n';