diff --git a/kcm/config_handler.cpp b/kcm/config_handler.cpp
index ce1ce0f18e1097b8040fb2cbd28bc9b533da8bce..3aea6b15a6e5f083a5a2912f16bd713ec2d23033 100644
--- a/kcm/config_handler.cpp
+++ b/kcm/config_handler.cpp
@@ -23,6 +23,7 @@ along with this program. If not, see .
#include
#include
+#include
#include
using namespace KScreen;
@@ -97,6 +98,7 @@ void ConfigHandler::initOutput(const KScreen::OutputPtr &output)
void ConfigHandler::updateInitialData()
{
+ m_previousConfig = m_initialConfig->clone();
m_initialRetention = getRetention();
connect(new GetConfigOperation(), &GetConfigOperation::finished, this, [this](ConfigOperation *op) {
if (op->hasError()) {
@@ -111,6 +113,11 @@ void ConfigHandler::updateInitialData()
});
}
+bool ConfigHandler::shouldTestNewSettings()
+{
+ return checkSaveandTestCommon(false);
+}
+
void ConfigHandler::checkNeedsSave()
{
if (m_config->supportedFeatures() & KScreen::Config::Feature::PrimaryDisplay) {
@@ -129,40 +136,44 @@ void ConfigHandler::checkNeedsSave()
Q_EMIT needsSaveChecked(true);
return;
}
+ Q_EMIT needsSaveChecked(checkSaveandTestCommon(true));
+}
- for (const auto &output : m_config->connectedOutputs()) {
+bool ConfigHandler::checkSaveandTestCommon(bool isSaveCheck)
+{
+ const auto outputs = m_config->connectedOutputs();
+ for (const auto &output : outputs) {
const QString hash = output->hashMd5();
- for (const auto &initialOutput : m_initialConfig->outputs()) {
- if (hash != initialOutput->hashMd5()) {
+ const auto configs = m_initialConfig->outputs();
+ for (const auto &config : configs) {
+ if (hash != config->hashMd5()) {
continue;
}
- bool needsSave = false;
- if (output->isEnabled() != initialOutput->isEnabled()) {
- needsSave = true;
+
+ if (output->isEnabled() != config->isEnabled()) {
+ return true;
}
+
// clang-format off
if (output->isEnabled()) {
- needsSave |= output->currentModeId() !=
- initialOutput->currentModeId()
- || output->pos() != initialOutput->pos()
- || output->scale() != initialOutput->scale()
- || output->rotation() != initialOutput->rotation()
- || output->replicationSource() != initialOutput->replicationSource()
- || autoRotate(output) != m_initialControl->getAutoRotate(output)
- || autoRotateOnlyInTabletMode(output)
- != m_initialControl->getAutoRotateOnlyInTabletMode(output)
- || output->overscan() != initialOutput->overscan()
- || output->vrrPolicy() != initialOutput->vrrPolicy();
+ bool realScaleChange = output->scale() != config->scale();
+ bool scaleChanged = isSaveCheck ? realScaleChange : qGuiApp->platformName() == QLatin1String("wayland") ? realScaleChange : false;
+ if ( output->currentModeId() != config->currentModeId()
+ || output->pos() != config->pos()
+ || scaleChanged
+ || output->rotation() != config->rotation()
+ || output->replicationSource() != config->replicationSource()
+ || autoRotate(output) != m_initialControl->getAutoRotate(output)
+ || autoRotateOnlyInTabletMode(output) != m_initialControl->getAutoRotateOnlyInTabletMode(output)
+ || output->overscan() != config->overscan()
+ || output->vrrPolicy() != config->vrrPolicy()) {
+ return true;
+ }
}
// clang-format on
- if (needsSave) {
- Q_EMIT needsSaveChecked(true);
- return;
- }
- break;
}
}
- Q_EMIT needsSaveChecked(false);
+ return false;
}
QSize ConfigHandler::screenSize() const
diff --git a/kcm/config_handler.h b/kcm/config_handler.h
index ad3fb11b451850e5772f2df2879c1704fe42e705..c8dfd8694295c771d98aaf705bc7efcf53fdd283 100644
--- a/kcm/config_handler.h
+++ b/kcm/config_handler.h
@@ -51,6 +51,11 @@ public:
return m_initialConfig;
}
+ void revertConfig()
+ {
+ m_config = m_previousConfig->clone();
+ }
+
int retention() const;
void setRetention(int retention);
@@ -74,6 +79,7 @@ public:
void writeControl();
void checkNeedsSave();
+ bool shouldTestNewSettings();
Q_SIGNALS:
void outputModelChanged();
@@ -91,9 +97,17 @@ private:
void primaryOutputChanged(const KScreen::OutputPtr &output);
void initOutput(const KScreen::OutputPtr &output);
void resetScale(const KScreen::OutputPtr &output);
+ /**
+ * @brief checkSaveandTestCommon - compairs common config changes that would make the config dirty and needed to have the config checked when applied.
+ * @param isSaveCheck - True if your checking to see if the changes should request a save.
+ * False if you want to check if you should test the config when applied.
+ * @return true, if you should check for a save or test the new configuration
+ */
+ bool checkSaveandTestCommon(bool isSaveCheck);
KScreen::ConfigPtr m_config = nullptr;
KScreen::ConfigPtr m_initialConfig;
+ KScreen::ConfigPtr m_previousConfig = nullptr;
OutputModel *m_outputs = nullptr;
std::unique_ptr m_control;
diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp
index 90bc0dd0c3df8af9706d7b227bc36a5b868f223d..bd5ff04adf40fd2ee263c9c81ce373d232dc4840 100644
--- a/kcm/kcm.cpp
+++ b/kcm/kcm.cpp
@@ -100,6 +100,21 @@ void KCMKScreen::save()
doSave(false);
}
+void KCMKScreen::revertSettings()
+{
+ if (!m_config) {
+ setNeedsSave(false);
+ return;
+ }
+ if (!m_settingsReverted) {
+ m_config->revertConfig();
+ m_settingsReverted = true;
+ doSave(true);
+ load(); // reload the configuration
+ Q_EMIT settingsReverted();
+ }
+}
+
void KCMKScreen::doSave(bool force)
{
if (!m_config) {
@@ -158,6 +173,12 @@ void KCMKScreen::doSave(bool force)
return;
}
m_config->updateInitialData();
+
+ if (!m_settingsReverted && m_config->shouldTestNewSettings()) {
+ Q_EMIT showRevertWarning();
+ } else {
+ m_settingsReverted = false;
+ }
});
}
diff --git a/kcm/kcm.h b/kcm/kcm.h
index b33eaa7c17acaf26698877e5e291d72a80ebf965..e29a30ddaf56b403e512b393305678be6f16b1ae 100644
--- a/kcm/kcm.h
+++ b/kcm/kcm.h
@@ -77,6 +77,7 @@ public:
Q_INVOKABLE void forceSave();
void doSave(bool force);
+ Q_INVOKABLE void revertSettings();
Q_SIGNALS:
void backendReadyChanged();
@@ -96,6 +97,8 @@ Q_SIGNALS:
void errorOnSave();
void globalScaleWritten();
void outputConnect(bool connected);
+ void settingsReverted();
+ void showRevertWarning();
private:
void setBackendReady(bool error);
@@ -112,6 +115,7 @@ private:
OrientationSensor *m_orientationSensor;
bool m_backendReady = false;
bool m_screenNormalized = true;
+ bool m_settingsReverted = false;
double m_globalScale = 1.;
double m_initialGlobalScale = 1.;
diff --git a/kcm/package/contents/ui/main.qml b/kcm/package/contents/ui/main.qml
index 8cb3375d7268821f5f8952eb70ca215ca636ef5b..15bb16f017f1ebcd21b318adf2929dcbbcf970ea 100644
--- a/kcm/package/contents/ui/main.qml
+++ b/kcm/package/contents/ui/main.qml
@@ -16,9 +16,9 @@ along with this program. If not, see .
*********************************************************************/
import QtQuick 2.15
import QtQuick.Layouts 1.1
-import QtQuick.Controls 2.3 as Controls
-import org.kde.kirigami 2.4 as Kirigami
+import QtQuick.Controls 2.15 as Controls
+import org.kde.kirigami 2.7 as Kirigami
import org.kde.kcm 1.2 as KCM
KCM.SimpleKCM {
@@ -28,6 +28,7 @@ KCM.SimpleKCM {
implicitHeight: Kirigami.Units.gridUnit * 38
property int selectedOutput: 0
+ property int revertCountdown: 30
ColumnLayout {
Kirigami.InlineMessage {
@@ -86,6 +87,74 @@ KCM.SimpleKCM {
visible: false
showCloseButton: true
}
+ Kirigami.InlineMessage {
+ id: revertMsg
+ Layout.fillWidth: true
+ type: Kirigami.MessageType.Information
+ text: i18n("Display configuration reverted.")
+ visible: false
+ showCloseButton: true
+ }
+ Kirigami.OverlaySheet {
+ id: confirmMsg
+ property bool keepConfig: false
+ property bool userInteraction: false
+ parent: root.parent
+ title: i18n("Keep display configuration?")
+ onSheetOpenChanged: {
+ if (sheetOpen) {
+ revertButton.forceActiveFocus()
+ confirmMsg.keepConfig = false
+ confirmMsg.userInteraction = false
+ } else {
+ if (!confirmMsg.keepConfig) {
+ kcm.revertSettings()
+ if (!confirmMsg.userInteraction) {
+ revertMsg.visible = true
+ }
+ }
+ revertTimer.stop()
+ }
+ }
+ showCloseButton: false
+ contentItem: Controls.Label {
+ text: i18np("Will revert to previous configuration in %1 second.",
+ "Will revert to previous configuration in %1 seconds.",
+ revertCountdown);
+ wrapMode: Qt.WordWrap
+ }
+ footer: RowLayout {
+ Controls.Button {
+ id: acceptButton
+ Layout.fillWidth: true
+ action: Controls.Action {
+ icon.name: "dialog-ok"
+ text: i18n("&Keep")
+ shortcut: "Return"
+ onTriggered: {
+ confirmMsg.keepConfig = true
+ confirmMsg.userInteraction = true
+ confirmMsg.close()
+ }
+ }
+ }
+ Controls.Button {
+ id: revertButton
+ Layout.fillWidth: true
+ KeyNavigation.left: acceptButton
+ focus: true
+ action: Controls.Action {
+ icon.name: "edit-undo"
+ text: i18n("&Revert")
+ shortcut: "Escape"
+ onTriggered: {
+ confirmMsg.userInteraction = true
+ confirmMsg.close()
+ }
+ }
+ }
+ }
+ }
Connections {
target: kcm
@@ -109,11 +178,19 @@ KCM.SimpleKCM {
function onBackendError() {
errBackendMsg.visible = true;
}
-
+ function onSettingsReverted() {
+ confirmMsg.close();
+ }
+ function onShowRevertWarning() {
+ revertCountdown = 30;
+ confirmMsg.open();
+ revertTimer.restart();
+ }
function onChanged() {
dangerousSaveMsg.visible = false;
errSaveMsg.visible = false;
scaleMsg.visible = false;
+ revertMsg.visible = false;
}
}
@@ -133,5 +210,21 @@ KCM.SimpleKCM {
enabled: kcm.outputModel && kcm.backendReady
Layout.fillWidth: true
}
+
+ Timer {
+ id: revertTimer
+ interval: 1000
+ running: false
+ repeat: true
+
+ onTriggered: {
+ revertCountdown -= 1;
+ if (revertCountdown < 1) {
+ this.stop();
+ kcm.revertSettings();
+ return;
+ }
+ }
+ }
}
}