Refactor power management classes

Mainly it is about moving each platform code to its own file.

PR #22279.
This commit is contained in:
Chocobo1 2025-02-18 11:58:43 +08:00 committed by GitHub
commit 1043bea896
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 379 additions and 115 deletions

View file

@ -69,6 +69,7 @@ add_library(qbt_gui STATIC
log/logmodel.h
mainwindow.h
optionsdialog.h
powermanagement/inhibitor.h
powermanagement/powermanagement.h
previewlistdelegate.h
previewselectdialog.h
@ -167,6 +168,7 @@ add_library(qbt_gui STATIC
log/logmodel.cpp
mainwindow.cpp
optionsdialog.cpp
powermanagement/inhibitor.cpp
powermanagement/powermanagement.cpp
previewlistdelegate.cpp
previewselectdialog.cpp
@ -259,8 +261,8 @@ if (DBUS)
notifications/dbusnotifier.cpp
notifications/dbusnotificationsinterface.h
notifications/dbusnotificationsinterface.cpp
powermanagement/powermanagement_x11.h
powermanagement/powermanagement_x11.cpp
powermanagement/inhibitordbus.h
powermanagement/inhibitordbus.cpp
)
endif()
@ -274,13 +276,6 @@ if (STACKTRACE)
)
endif()
if ((CMAKE_SYSTEM_NAME STREQUAL "Windows") OR (CMAKE_SYSTEM_NAME STREQUAL "Darwin"))
target_sources(qbt_gui PRIVATE
programupdater.h
programupdater.cpp
)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
target_sources(qbt_gui PRIVATE
macosdockbadge/badger.h
@ -289,6 +284,19 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
macosdockbadge/badgeview.mm
macutilities.h
macutilities.mm
powermanagement/inhibitormacos.h
powermanagement/inhibitormacos.cpp
programupdater.h
programupdater.cpp
)
target_link_libraries(qbt_gui PRIVATE objc)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
target_sources(qbt_gui PRIVATE
powermanagement/inhibitorwindows.h
powermanagement/inhibitorwindows.cpp
programupdater.h
programupdater.cpp
)
endif()

View file

@ -130,6 +130,8 @@ MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, con
, m_ui {new Ui::MainWindow}
, m_downloadRate {Utils::Misc::friendlyUnit(0, true)}
, m_uploadRate {Utils::Misc::friendlyUnit(0, true)}
, m_pwr {new PowerManagement}
, m_preventTimer {new QTimer(this)}
, m_storeExecutionLogEnabled {EXECUTIONLOG_SETTINGS_KEY(u"Enabled"_s)}
, m_storeDownloadTrackerFavicon {SETTINGS_KEY(u"DownloadTrackerFavicon"_s)}
, m_storeExecutionLogTypes {EXECUTIONLOG_SETTINGS_KEY(u"Types"_s), Log::MsgType::ALL}
@ -336,8 +338,6 @@ MainWindow::MainWindow(IGUIApplication *app, const WindowState initialState, con
connect(m_ui->actionManageCookies, &QAction::triggered, this, &MainWindow::manageCookies);
// Initialise system sleep inhibition timer
m_pwr = new PowerManagement(this);
m_preventTimer = new QTimer(this);
m_preventTimer->setSingleShot(true);
connect(m_preventTimer, &QTimer::timeout, this, &MainWindow::updatePowerManagementState);
connect(pref, &Preferences::changed, this, &MainWindow::updatePowerManagementState);
@ -837,6 +837,7 @@ void MainWindow::cleanup()
delete m_executableWatcher;
m_preventTimer->stop();
delete m_pwr;
#if (defined(Q_OS_WIN) || defined(Q_OS_MACOS))
if (m_programUpdateTimer)
@ -1826,7 +1827,7 @@ void MainWindow::updatePowerManagementState() const
return torrent->isMoving();
});
m_pwr->setActivityState(inhibitSuspend);
m_pwr->setActivityState(inhibitSuspend ? PowerManagement::ActivityState::Busy : PowerManagement::ActivityState::Idle);
m_preventTimer->start(PREVENT_SUSPEND_INTERVAL);
}

View file

@ -0,0 +1,40 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2011 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "inhibitor.h"
bool Inhibitor::requestBusy()
{
return true;
}
bool Inhibitor::requestIdle()
{
return true;
}

View file

@ -0,0 +1,38 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
class Inhibitor
{
public:
virtual ~Inhibitor() = default;
virtual bool requestBusy();
virtual bool requestIdle();
};

View file

@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2011 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
@ -26,7 +27,7 @@
* exception statement from your version.
*/
#include "powermanagement_x11.h"
#include "inhibitordbus.h"
#include <QDBusConnection>
#include <QDBusInterface>
@ -36,7 +37,7 @@
#include "base/global.h"
#include "base/logger.h"
PowerManagementInhibitor::PowerManagementInhibitor(QObject *parent)
InhibitorDBus::InhibitorDBus(QObject *parent)
: QObject(parent)
, m_busInterface {new QDBusInterface(u"org.gnome.SessionManager"_s, u"/org/gnome/SessionManager"_s
, u"org.gnome.SessionManager"_s, QDBusConnection::sessionBus(), this)}
@ -70,38 +71,26 @@ PowerManagementInhibitor::PowerManagementInhibitor(QObject *parent)
}
else
{
m_state = Error;
LogMsg(tr("Power management error. Did not found suitable D-Bus interface."), Log::WARNING);
}
}
void PowerManagementInhibitor::requestIdle()
{
m_intendedState = Idle;
if ((m_state == Error) || (m_state == Idle) || (m_state == RequestIdle) || (m_state == RequestBusy))
return;
if (m_manager == ManagerType::Systemd)
{
m_fd = {};
m_state = Idle;
return;
}
m_state = RequestIdle;
const QString method = (m_manager == ManagerType::Gnome)
? u"Uninhibit"_s
: u"UnInhibit"_s;
const QDBusPendingCall pcall = m_busInterface->asyncCall(method, m_cookie);
const auto *watcher = new QDBusPendingCallWatcher(pcall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInhibitor::onAsyncReply);
}
void PowerManagementInhibitor::requestBusy()
bool InhibitorDBus::requestBusy()
{
m_intendedState = Busy;
if ((m_state == Error) || (m_state == Busy) || (m_state == RequestBusy) || (m_state == RequestIdle))
return;
switch (m_state)
{
case Busy:
case RequestBusy:
return true;
case Error:
case RequestIdle:
return false;
case Idle:
break;
};
m_state = RequestBusy;
@ -123,10 +112,45 @@ void PowerManagementInhibitor::requestBusy()
const QDBusPendingCall pcall = m_busInterface->asyncCallWithArgumentList(u"Inhibit"_s, args);
const auto *watcher = new QDBusPendingCallWatcher(pcall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInhibitor::onAsyncReply);
connect(watcher, &QDBusPendingCallWatcher::finished, this, &InhibitorDBus::onAsyncReply);
return true;
}
void PowerManagementInhibitor::onAsyncReply(QDBusPendingCallWatcher *call)
bool InhibitorDBus::requestIdle()
{
m_intendedState = Idle;
switch (m_state)
{
case Idle:
case RequestIdle:
return true;
case Error:
case RequestBusy:
return false;
case Busy:
break;
};
if (m_manager == ManagerType::Systemd)
{
m_fd = {};
m_state = Idle;
return true;
}
m_state = RequestIdle;
const QString method = (m_manager == ManagerType::Gnome)
? u"Uninhibit"_s
: u"UnInhibit"_s;
const QDBusPendingCall pcall = m_busInterface->asyncCall(method, m_cookie);
const auto *watcher = new QDBusPendingCallWatcher(pcall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, &InhibitorDBus::onAsyncReply);
return true;
}
void InhibitorDBus::onAsyncReply(QDBusPendingCallWatcher *call)
{
call->deleteLater();

View file

@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2011 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
@ -31,20 +32,21 @@
#include <QDBusUnixFileDescriptor>
#include <QObject>
#include "inhibitor.h"
class QDBusInterface;
class QDBusPendingCallWatcher;
class PowerManagementInhibitor final : public QObject
class InhibitorDBus final : public QObject, public Inhibitor
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(PowerManagementInhibitor)
Q_DISABLE_COPY_MOVE(InhibitorDBus)
public:
PowerManagementInhibitor(QObject *parent = nullptr);
~PowerManagementInhibitor() override = default;
InhibitorDBus(QObject *parent = nullptr);
void requestIdle();
void requestBusy();
bool requestBusy() override;
bool requestIdle() override;
private slots:
void onAsyncReply(QDBusPendingCallWatcher *call);

View file

@ -0,0 +1,46 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2011 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "inhibitormacos.h"
#include <QScopeGuard>
bool InhibitorMacOS::requestBusy()
{
const CFStringRef assertName = tr("PMMacOS", "qBittorrent is active").toCFString();
[[maybe_unused]] const auto assertNameGuard = qScopeGuard([&assertName] { ::CFRelease(assertName); });
const IOReturn result = ::IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn
, assertName, &m_assertionID);
return result == kIOReturnSuccess;
}
bool InhibitorMacOS::requestIdle()
{
return ::IOPMAssertionRelease(m_assertionID) == kIOReturnSuccess;
}

View file

@ -0,0 +1,47 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <QCoreApplication>
#include "inhibitor.h"
class InhibitorMacOS final : public Inhibitor
{
Q_DECLARE_TR_FUNCTIONS(InhibitorMacOS)
public:
bool requestBusy() override;
bool requestIdle() override;
private:
IOPMAssertionID m_assertionID {};
};

View file

@ -0,0 +1,42 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2011 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#include "inhibitorwindows.h"
#include <windows.h>
bool InhibitorWindows::requestBusy()
{
return ::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) != NULL;
}
bool InhibitorWindows::requestIdle()
{
return ::SetThreadExecutionState(ES_CONTINUOUS) != NULL;
}

View file

@ -0,0 +1,38 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* In addition, as a special exception, the copyright holders give permission to
* link this program with the OpenSSL project's "OpenSSL" library (or with
* modified versions of it that use the same license as the "OpenSSL" library),
* and distribute the linked executables. You must obey the GNU General Public
* License in all respects for all of the code used other than "OpenSSL". If you
* modify file(s), you may extend this exception to your version of the file(s),
* but you are not obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
#pragma once
#include "inhibitor.h"
class InhibitorWindows final : public Inhibitor
{
public:
bool requestBusy() override;
bool requestIdle() override;
};

View file

@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2011 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
@ -30,71 +31,59 @@
#include <QtSystemDetection>
#ifdef Q_OS_MACOS
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <QScopeGuard>
#if defined(Q_OS_MACOS)
#include "inhibitormacos.h"
using InhibitorImpl = InhibitorMacOS;
#elif defined(Q_OS_WIN)
#include "inhibitorwindows.h"
using InhibitorImpl = InhibitorWindows;
#elif defined(QBT_USES_DBUS)
#include "inhibitordbus.h"
using InhibitorImpl = InhibitorDBus;
#else
#include "inhibitor.h"
using InhibitorImpl = Inhibitor;
#endif
#ifdef Q_OS_WIN
#include <windows.h>
#endif
#ifdef QBT_USES_DBUS
#include "powermanagement_x11.h"
#endif
PowerManagement::PowerManagement(QObject *parent)
: QObject(parent)
#ifdef QBT_USES_DBUS
, m_inhibitor {new PowerManagementInhibitor(this)}
#endif
PowerManagement::PowerManagement()
: m_inhibitor {new InhibitorImpl}
{
}
PowerManagement::~PowerManagement()
{
setIdle();
delete m_inhibitor;
}
void PowerManagement::setActivityState(const bool busy)
void PowerManagement::setActivityState(const ActivityState state)
{
if (busy)
switch (state)
{
case ActivityState::Busy:
setBusy();
else
break;
case ActivityState::Idle:
setIdle();
break;
};
}
void PowerManagement::setBusy()
{
if (m_busy)
if (m_state == ActivityState::Busy)
return;
m_busy = true;
#ifdef Q_OS_WIN
::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
#elif defined(QBT_USES_DBUS)
m_inhibitor->requestBusy();
#elif defined(Q_OS_MACOS)
const CFStringRef assertName = tr("qBittorrent is active").toCFString();
[[maybe_unused]] const auto assertNameGuard = qScopeGuard([&assertName] { ::CFRelease(assertName); });
const IOReturn success = ::IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn
, assertName, &m_assertionID);
if (success != kIOReturnSuccess)
m_busy = false;
#endif
if (m_inhibitor->requestBusy())
m_state = ActivityState::Busy;
}
void PowerManagement::setIdle()
{
if (!m_busy)
if (m_state == ActivityState::Idle)
return;
m_busy = false;
#ifdef Q_OS_WIN
::SetThreadExecutionState(ES_CONTINUOUS);
#elif defined(QBT_USES_DBUS)
m_inhibitor->requestIdle();
#elif defined(Q_OS_MACOS)
::IOPMAssertionRelease(m_assertionID);
#endif
if (m_inhibitor->requestIdle())
m_state = ActivityState::Idle;
}

View file

@ -1,5 +1,6 @@
/*
* Bittorrent Client using Qt and libtorrent.
* Copyright (C) 2025 Mike Tzou (Chocobo1)
* Copyright (C) 2011 Vladimir Golovnev <glassez@yandex.ru>
*
* This program is free software; you can redistribute it and/or
@ -28,38 +29,26 @@
#pragma once
#include <QObject>
class Inhibitor;
#ifdef Q_OS_MACOS
// Require Mac OS X >= 10.5
#include <IOKit/pwr_mgt/IOPMLib.h>
#endif
#ifdef QBT_USES_DBUS
class PowerManagementInhibitor;
#endif
class PowerManagement final : public QObject
class PowerManagement final
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(PowerManagement)
public:
PowerManagement(QObject *parent = nullptr);
~PowerManagement() override;
enum class ActivityState
{
Busy,
Idle
};
void setActivityState(bool busy);
PowerManagement();
~PowerManagement();
void setActivityState(ActivityState state);
private:
void setBusy();
void setIdle();
bool m_busy = false;
#ifdef QBT_USES_DBUS
PowerManagementInhibitor *m_inhibitor = nullptr;
#endif
#ifdef Q_OS_MACOS
IOPMAssertionID m_assertionID {};
#endif
ActivityState m_state = ActivityState::Idle;
Inhibitor *m_inhibitor = nullptr;
};