Commit ff605967 authored by Juan Palacios's avatar Juan Palacios

Merge branch 'workaround-high_cpu_load'

Workaround for #29
parents d79696ca d2ce4286
......@@ -269,6 +269,8 @@ list (APPEND TRANSLATABLE_FILES
qml/System.qml
qml/About.qml
qml/SettingsDialog.qml
qml/SettingsGeneral.qml
qml/SettingsWorkarounds.qml
qml/SysModelForm.qml
qml/CPUForm.qml
qml/GPUForm.qml
......
......@@ -127,6 +127,9 @@ int App::exec(int argc, char **argv)
QQmlApplicationEngine qmlEngine;
buildUI(qmlEngine);
// Load and apply stored settings
settings_->signalSettings();
return app.exec();
}
catch (std::exception const &e) {
......@@ -158,17 +161,23 @@ void App::showMainWindow()
}
}
void App::onSettingChanged(QString const &key, QVariant const &value)
{
sysTray_->settingChanged(key, value);
sysSyncer_->settingChanged(key, value);
}
void App::buildUI(QQmlApplicationEngine &qmlEngine)
{
connect(&qmlEngine, &QQmlApplicationEngine::quit, QApplication::instance(),
&QApplication::quit);
connect(QApplication::instance(), &QApplication::aboutToQuit, this, &App::exit);
connect(settings_.get(), &Settings::settingChanged, this,
&App::onSettingChanged);
sysTray_ = std::make_unique<SysTray>(this);
if (settings_->getValue("sysTray", true).toBool())
sysTray_->show();
connect(settings_.get(), &Settings::settingChanged, sysTray_.get(),
&SysTray::onSettingChanged);
qmlEngine.rootContext()->setContextProperty("appInfo", &appInfo_);
qmlEngine.rootContext()->setContextProperty("settings", settings_.get());
......
......@@ -81,6 +81,7 @@ class App final : public QObject
private slots:
void exit();
void showMainWindow();
void onSettingChanged(QString const &key, QVariant const &value);
private:
void buildUI(QQmlApplicationEngine &qmlEngine);
......
......@@ -34,3 +34,27 @@ QVariant Settings::getValue(QString const &key, QVariant const &defaultValue) co
value.convert(static_cast<int>(defaultValue.type()));
return value;
}
void Settings::setStringList(QString const &key, QStringList const &list)
{
if (list.empty())
QSettings::remove(key);
else
QSettings::setValue(key, list);
emit settingChanged(key, list);
}
QVariant Settings::getStringList(QString const &key,
QStringList const &defaultValue) const
{
auto value = QSettings::value(key, defaultValue);
return value.toStringList();
}
void Settings::signalSettings()
{
auto keys = QSettings::allKeys();
for (auto &key : keys)
emit settingChanged(key, QSettings::value(key));
}
......@@ -30,6 +30,12 @@ class Settings final : public QSettings
Q_INVOKABLE QVariant getValue(QString const &key,
QVariant const &defaultValue) const;
Q_INVOKABLE void setStringList(QString const &key, QStringList const &list);
Q_INVOKABLE QVariant getStringList(QString const &key,
QStringList const &defaultList) const;
void signalSettings();
signals:
void settingChanged(QString const &key, QVariant const &value);
};
......@@ -56,7 +56,7 @@ void SysTray::hide()
sysTray_->hide();
}
void SysTray::onSettingChanged(QString const &key, QVariant const &value)
void SysTray::settingChanged(QString const &key, QVariant const &value)
{
if (key == "sysTray")
sysTray_->setVisible(value.toBool());
......
......@@ -36,7 +36,7 @@ class SysTray : public QObject
public slots:
void show();
void hide();
void onSettingChanged(QString const &key, QVariant const &value);
void settingChanged(QString const &key, QVariant const &value);
private slots:
void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason);
......
......@@ -97,10 +97,15 @@ void CPU::sync(ICommandQueue &ctlCmds)
}
}
void CPU::updateSensors()
void CPU::updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const &ignored)
{
for (auto &sensor : sensors_)
for (auto &sensor : sensors_) {
if (ignored.count(key_) > 0 && ignored.at(key_).count(sensor->ID()) > 0)
continue; // skip ignored sensors
sensor->update();
}
}
ICPUInfo const &CPU::info() const
......
......@@ -46,7 +46,9 @@ class CPU final : public ICPU
void postInit(ICommandQueue &ctlCmds) override;
void sync(ICommandQueue &ctlCmds) override;
void updateSensors() override;
void updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const
&ignored) override;
ICPUInfo const &info() const override;
......
......@@ -28,6 +28,7 @@ class CPUQMLItem
, public ICPUProfilePart::Exporter
{
Q_OBJECT
Q_PROPERTY(int socketId READ provideSocketId)
public:
void activate(bool active) override;
......
......@@ -97,10 +97,15 @@ void GPU::sync(ICommandQueue &ctlCmds)
}
}
void GPU::updateSensors()
void GPU::updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const &ignored)
{
for (auto &sensor : sensors_)
for (auto &sensor : sensors_) {
if (ignored.count(key_) > 0 && ignored.at(key_).count(sensor->ID()) > 0)
continue; // skip ignored sensors
sensor->update();
}
}
IGPUInfo const &GPU::info() const
......
......@@ -46,7 +46,9 @@ class GPU final : public IGPU
void postInit(ICommandQueue &ctlCmds) override;
void sync(ICommandQueue &ctlCmds) override;
void updateSensors() override;
void updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const
&ignored) override;
IGPUInfo const &info() const override;
......
......@@ -28,6 +28,7 @@ class GPUQMLItem
, public IGPUProfilePart::Exporter
{
Q_OBJECT
Q_PROPERTY(int index READ provideIndex)
public:
void activate(bool active) override;
......
......@@ -66,7 +66,7 @@ void GraphItem::initialRange(qreal min, qreal max)
void GraphItem::updateGraph(qreal value)
{
if (series_ != nullptr) {
if (series_ != nullptr && !ignored()) {
if (points_.size() == PointsCount)
points_.removeFirst();
......@@ -90,11 +90,10 @@ void GraphItem::updateGraph(qreal value)
// update axes
xAxis_->setRange(newX - PointsCount + 1, newX);
updateYAxis(value);
}
// always update the value of the item
value_ = value;
emit valueChanged(value);
value_ = value;
emit valueChanged(value);
}
}
std::optional<std::reference_wrapper<Importable::Importer>>
......@@ -188,6 +187,23 @@ void GraphItem::active(bool active)
}
}
bool GraphItem::ignored() const
{
return ignored_;
}
void GraphItem::ignored(bool ignored)
{
if (ignored_ != ignored) {
ignored_ = ignored;
if (series_ != nullptr)
series_->setVisible(active_ && !ignored_);
emit ignoredChanged(ignored);
}
}
void GraphItem::updateYAxis(qreal value)
{
if (value < yMin_ || value > yMax_) {
......
......@@ -36,6 +36,7 @@ class GraphItem
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
Q_PROPERTY(qreal value READ value NOTIFY valueChanged)
Q_PROPERTY(bool active READ active WRITE active NOTIFY activeChanged)
Q_PROPERTY(bool ignored READ ignored WRITE ignored NOTIFY ignoredChanged)
Q_PROPERTY(QString unit READ unit)
Q_PROPERTY(QString color READ color)
......@@ -78,11 +79,14 @@ class GraphItem
void valueChanged(qreal value);
void activeChanged(bool active);
void colorChanged(QString const &color);
void ignoredChanged(bool ignored);
void yAxisRangeChanged(qreal min, qreal max);
private:
bool active() const;
void active(bool active);
bool ignored() const;
void ignored(bool ignored);
void updateYAxis(qreal value);
void restartXPoints();
......@@ -93,6 +97,7 @@ class GraphItem
std::string color_{"white"};
bool active_{true};
bool ignored_{false};
qreal value_{0};
......
......@@ -21,6 +21,8 @@
#include "importable.h"
#include "item.h"
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
class ICommandQueue;
......@@ -58,7 +60,9 @@ class ISysComponent
virtual void preInit(ICommandQueue &ctlCmds) = 0;
virtual void postInit(ICommandQueue &ctlCmds) = 0;
virtual void sync(ICommandQueue &ctlCmds) = 0;
virtual void updateSensors() = 0;
virtual void updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const
&ignored) = 0;
virtual ~ISysComponent() = default;
};
......@@ -21,6 +21,8 @@
#include "core/importable.h"
#include "core/item.h"
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
class ICommandQueue;
......@@ -47,7 +49,9 @@ class ISysModel
virtual void preInit(ICommandQueue &ctlCmds) = 0;
virtual void postInit(ICommandQueue &ctlCmds) = 0;
virtual void sync(ICommandQueue &ctlCmds) = 0;
virtual void updateSensors() = 0;
virtual void updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const
&ignored) = 0;
virtual std::vector<
std::pair<std::string, std::vector<std::pair<std::string, std::string>>>>
......
......@@ -18,11 +18,14 @@
#pragma once
class ISysModel;
class QString;
class QVariant;
class ISysModelSyncer
{
public:
virtual ISysModel &sysModel() const = 0;
virtual void settingChanged(QString const &key, QVariant const &value) = 0;
virtual void init() = 0;
virtual void stop() = 0;
......
......@@ -57,10 +57,11 @@ void SysModel::sync(ICommandQueue &ctlCmds)
component->sync(ctlCmds);
}
void SysModel::updateSensors()
void SysModel::updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const &ignored)
{
for (auto &component : components_)
component->updateSensors();
component->updateSensors(ignored);
}
std::vector<std::pair<std::string, std::vector<std::pair<std::string, std::string>>>>
......
......@@ -33,7 +33,9 @@ class SysModel final : public ISysModel
void preInit(ICommandQueue &ctlCmds) override;
void postInit(ICommandQueue &ctlCmds) override;
void sync(ICommandQueue &ctlCmds) override;
void updateSensors() override;
void updateSensors(
std::unordered_map<std::string, std::unordered_set<std::string>> const
&ignored) override;
std::vector<std::pair<std::string, std::vector<std::pair<std::string, std::string>>>>
info() const override;
......
......@@ -18,6 +18,7 @@
#include "sysmodelsyncer.h"
#include "iprofileview.h"
#include <QVariant>
#include <chrono>
SysModelSyncer::SysModelSyncer(std::unique_ptr<ISysModel> &&sysModel,
......@@ -32,6 +33,28 @@ ISysModel &SysModelSyncer::sysModel() const
return *sysModel_;
}
void SysModelSyncer::settingChanged(QString const &key, QVariant const &value)
{
if (key == "Workarounds/ignoredSensors") {
std::lock_guard<std::mutex> lock(sensorsMutex_);
ignoredSensors_.clear();
auto sensorList = value.toStringList();
for (auto &sensor : sensorList) {
auto componentSensorIdList = sensor.split('/');
if (componentSensorIdList.size() == 2) {
auto component = componentSensorIdList.at(0).toStdString();
auto sensorId = componentSensorIdList.at(1).toStdString();
if (ignoredSensors_.count(component) == 0)
ignoredSensors_[component] = {};
ignoredSensors_[component].emplace(sensorId);
}
}
}
}
void SysModelSyncer::init()
{
helperSysCtl_->init();
......@@ -80,7 +103,8 @@ void SysModelSyncer::apply(IProfileView &profileView)
void SysModelSyncer::updateSensors()
{
sysModel_->updateSensors();
std::lock_guard<std::mutex> lock(sensorsMutex_);
sysModel_->updateSensors(ignoredSensors_);
}
void SysModelSyncer::syncModel()
......
......@@ -40,6 +40,7 @@ class SysModelSyncer final
std::unique_ptr<IHelperSysCtl> &&helperSysCtl) noexcept;
ISysModel &sysModel() const override;
void settingChanged(QString const &key, QVariant const &value) override;
void init() override;
void stop() override;
......@@ -56,6 +57,9 @@ class SysModelSyncer final
std::mutex syncMutex_;
CommandQueue cmds_;
std::mutex sensorsMutex_;
std::unordered_map<std::string, std::unordered_set<std::string>> ignoredSensors_;
std::unique_ptr<std::thread> updateThread_;
std::unique_ptr<std::thread> syncThread_;
std::atomic<bool> stopSignal_{false};
......
......@@ -15,9 +15,30 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// Distributed under the GPL version 3 or any later version.
//
.pragma library;
import QtQuick 2.0
import QtQuick.Controls 2.2
import "Style.js" as Style
var SysemTrayDefaults = {
enabled: true,
startMinimized: false,
};
GroupBox {
id: control
property alias showLine: bg.visible
label: Label {
text: control.title
font.pointSize: Style.GroupBox.text_size
font.bold: Style.GroupBox.text_bold
width: control.width
horizontalAlignment: Text.AlignHCenter
y: control.padding / 2
}
background: Rectangle {
id: bg
color: Style.GroupBox.bg_color
border.color: enabled ? Style.GroupBox.bg_border_color
: Style.GroupBox.bg_border_color_alt
radius: Style.GroupBox.bg_radius
}
}
......@@ -21,12 +21,18 @@ import QtQuick.Controls.Material 2.2
import QtQuick.Layouts 1.3
import Radman.UIComponents 1.0
import "Style.js" as Style
import "Settings.js" as Settings
CPU {
id: cpu
objectName: "CPU"
onNewGraphItem: sensorGraph.addItem(item)
onNewGraphItem: {
sensorGraph.addItem(item)
Settings.addComponentData("CPU" + cpu.socketId, "CPU " + cpu.socketId,
item.name,
qsTranslate("SensorGraph", item.name))
}
ColumnLayout {
spacing: 0
......@@ -35,6 +41,18 @@ CPU {
SensorGraph {
id: sensorGraph
Layout.fillWidth: true
Connections {
target: settings
onSettingChanged: {
if (key === "Workarounds/ignoredSensors") {
var sensors = Settings.componentIgnoredSensors("CPU" + cpu.socketId,
value)
sensorGraph.ignoredSensors(sensors)
}
}
}
}
Pane {
......
......@@ -21,12 +21,18 @@ import QtQuick.Controls.Material 2.2
import QtQuick.Layouts 1.3
import Radman.UIComponents 1.0
import "Style.js" as Style
import "Settings.js" as Settings
GPU {
id: gpu
objectName: "GPU"
onNewGraphItem: sensorGraph.addItem(item)
onNewGraphItem: {
sensorGraph.addItem(item)
Settings.addComponentData("GPU" + gpu.index, "GPU " + gpu.index,
item.name,
qsTranslate("SensorGraph", item.name))
}
ColumnLayout {
spacing: 0
......@@ -35,6 +41,18 @@ GPU {
SensorGraph {
id: sensorGraph
Layout.fillWidth: true
Connections {
target: settings
onSettingChanged: {
if (key === "Workarounds/ignoredSensors") {
var sensors = Settings.componentIgnoredSensors("GPU" + gpu.index,
value)
sensorGraph.ignoredSensors(sensors)
}
}
}
}
Pane {
......
......@@ -35,11 +35,23 @@ Rectangle {
p.addGrapItem(item)
}
function ignoredSensors(sensors) {
p.refreshIgnored(sensors)
}
QtObject { // private stuff
id: p
property var itemsArray: []
function refreshIgnored(sensors) {
for (var i = 0; i < itemsArray.length; ++i) {
itemsArray[i].ignored = sensors.some(function(item) {
return itemsArray[i].name === item
})
}
}
function updateItems() {
for (var i = 0; i < itemsArray.length; ++i)
itemsArray[i].update()
......@@ -80,6 +92,10 @@ Rectangle {
controlsModel.set(itemIndex, { "_color": color })
})
item.ignoredChanged.connect(function (ignored) {
controlsModel.set(itemIndex, { "_ignored": ignored})
})
item.yAxisRangeChanged.connect(function (min, max) {
for (var i = 0; i < itemsArray.length; ++i)
if (itemsArray[i] !== item && itemsArray[i].unit === item.unit)
......@@ -92,7 +108,8 @@ Rectangle {
"_value": item.value,
"_unit": item.unit,
"_color": item.color,
"_active": true })
"_active": true,
"_ignored": false })
}
}
......@@ -107,6 +124,7 @@ Rectangle {
RowLayout {
property var index: _index
spacing: 0
enabled: !_ignored
CheckBox {
checked: _active
......@@ -129,13 +147,14 @@ Rectangle {
}
Label {
text: _value
text: _ignored ? qsTr("n/a") : _value
font.pointSize: Style.g_text.size - 1
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
}
Label {
text: " " + _unit
visible: !_ignored
font.pointSize: Style.g_text.size - 1
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
}
......
//
// Copyright 2019 Juan Palacios <jpalaciosdev@gmail.com>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
// Distributed under the GPL version 3 or any later version.
//
.pragma library;
var SysemTrayDefaults = {
enabled: true,
startMinimized: false,
};
var ComponentData = {
components: [], // component labels indexed by component id
sensors: [] // sensors data indexed by component id
};
function addComponentData(componentId, componentLabel, sensorId, sensorLabel) {
if (ComponentData.components[componentId] === undefined)
ComponentData.components[componentId] = componentLabel
if (ComponentData.sensors[componentId] === undefined)
ComponentData.sensors[componentId] = []
var sensor = {
id: sensorId,
label: sensorLabel
};
ComponentData.sensors[componentId].push(sensor)
}
function componentIgnoredSensors(componentId, ignoredSensorsList) {
var sensorList = []
// Handle all input as a list.
// NOTE This is needed because QSettings will return a QString
// instead of a QStringList when there is only one ignored sensor.
if (typeof(ignoredSensorsList) === "string") {
var sensor = ignoredSensorsList
ignoredSensorsList = []
ignoredSensorsList.push(sensor)
}
for (var i = 0; i < ignoredSensorsList.length; ++i) {
var componentList = ignoredSensorsList[i].split('/')
if (componentId === componentList[0])
sensorList.push(componentList[1])
}
return sensorList
}
......@@ -17,8 +17,8 @@
//
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "Style.js" as Style
import "Global.js" as Global
Dialog {
id: settingsDlg
......@@ -34,36 +34,54 @@ Dialog {
x: (parent.width - width) / 2
y: (parent.height - height) / 2
Column {
CheckBox {
id: sysTrayIcon
text: qsTr("Show system tray icon")
ColumnLayout {
anchors.fill: parent
onToggled: footer.standardButton(Dialog.Ok).enabled = true
TabBar {
id: tabBar
Layout.fillWidth: true
hoverEnabled: Style.g_hover
Repeater {
model: [qsTr("General"), qsTr("Workarounds")]
TabButton {
text: modelData
background: Rectangle {
color: hovered ? Style.Dialog.tabs.bg_color_alt
: Style.Dialog.tabs.bg_color
}
}
}
}
CheckBox {
id: startOnSysTray
enabled: sysTrayIcon.enabled && sysTrayIcon.checked
text: qsTr("Start minimized on system tray")
StackLayout {
currentIndex: tabBar.currentIndex
SettingsGeneral {
id: general
onSettingsChanged: footer.standardButton(Dialog.Ok).enabled = true
}
onToggled: footer.standardButton(Dialog.Ok).enabled = true