From 630da7caaaaf504f2c1643278361f867b44551db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Tinkl?= Date: Thu, 22 Feb 2024 16:16:47 +0100 Subject: [PATCH] fix: 150% and 200% zoom levels prevent the user from logging in - TLDR: we were scaling twice, resulting in ginourmous pixel values The long story: - since Qt treats the various scale factors in a multiplicative way (see https://www.qt.io/blog/2016/01/26/high-dpi-support-in-qt-5-6 for explanation) and there's no way to get the screen's baseline scale factor programatically, we also have to export `QT_SCREEN_SCALE_FACTORS` to something that's not equal to `0` or `1` to force the monitor scale factor to `100%` and then compensate for it when exporting our own scale value using `QT_SCALE_FACTOR` - make the UI slider values go in `25%` steps, allowing for more fine grained control; with `100%` we fallback to the Qt's native handling of highdpi - raised the maximum to `300%` since on highres displays, one wouldn't be able to go over the implicit maximum of `200%` (due to the internal scaling being 2x) - scale our main window's minimum width/height so that we don't overflow the monitor's available space - modernize the `ConfirmAppRestartModal` to use `StatusDialog` - use the new `Utils.restartApplication()` when changing the UI language as well - remove some dead code In the (very) long term, we should take a different approach of scaling our app independently of Qt, just taking the monitor `Screen.devicePixelRatio` into account, similar to what other apps like Telegram do Fixes #13484 --- .../Profile/popups/ConfirmAppRestartModal.qml | 46 ++++-------- .../Profile/views/AppearanceView.qml | 71 ++++++++++--------- .../AppLayouts/Profile/views/LanguageView.qml | 5 +- ui/main.qml | 18 ++--- vendor/DOtherSide/lib/src/DOtherSide.cpp | 16 ++++- 5 files changed, 75 insertions(+), 81 deletions(-) diff --git a/ui/app/AppLayouts/Profile/popups/ConfirmAppRestartModal.qml b/ui/app/AppLayouts/Profile/popups/ConfirmAppRestartModal.qml index 065bc67628..9e71a61169 100644 --- a/ui/app/AppLayouts/Profile/popups/ConfirmAppRestartModal.qml +++ b/ui/app/AppLayouts/Profile/popups/ConfirmAppRestartModal.qml @@ -1,44 +1,26 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 -import QtQuick.Layouts 1.13 - -import utils 1.0 +import QtQuick 2.15 +import QtQml.Models 2.15 import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 +import StatusQ.Popups.Dialog 0.1 -import shared 1.0 -import shared.panels 1.0 -import shared.popups 1.0 - -// TODO: replace with StatusModal -ModalPopup { - height: 237 - width: 400 - - property Popup parentPopup - +StatusDialog { + id: root title: qsTr("Application Restart") - StyledText { + contentItem: StatusBaseText { text: qsTr("Please restart the application to apply the changes.") - font.pixelSize: 15 - anchors.left: parent.left - anchors.right: parent.right wrapMode: Text.WordWrap } - footer: Item { - id: footerContainer - width: parent.width - height: children[0].height - - StatusButton { - anchors.right: parent.right - anchors.rightMargin: Style.current.smallPadding - type: StatusBaseButton.Type.Danger - text: qsTr("Restart") - anchors.bottom: parent.bottom - onClicked: Utils.restartApplication(); + footer: StatusDialogFooter { + rightButtons: ObjectModel { + StatusButton { + type: StatusBaseButton.Type.Danger + text: qsTr("Restart") + onClicked: root.accepted() + } } } } diff --git a/ui/app/AppLayouts/Profile/views/AppearanceView.qml b/ui/app/AppLayouts/Profile/views/AppearanceView.qml index 519d0e4732..865bcf60c8 100644 --- a/ui/app/AppLayouts/Profile/views/AppearanceView.qml +++ b/ui/app/AppLayouts/Profile/views/AppearanceView.qml @@ -1,7 +1,8 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 -import QtQuick.Layouts 1.13 -import QtQuick.Controls.Universal 2.12 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Window 2.15 +import QtQuick.Controls.Universal 2.15 import utils 1.0 import shared 1.0 @@ -37,20 +38,29 @@ SettingsContentBase { appearanceView.updateFontSize(localAccountSensitiveSettings.fontSize) } + readonly property var priv: QtObject { + id: priv + + readonly property real savedDpr: { + const scaleFactorStr = appearanceView.appearanceStore.readTextFile(uiScaleFilePath) + if (scaleFactorStr === "") { + return 1 + } + const scaleFactor = parseFloat(scaleFactorStr) + if (isNaN(scaleFactor)) { + return 1 + } + return scaleFactor + } + } + Item { id: appearanceContainer anchors.left: !!parent ? parent.left : undefined + anchors.leftMargin: Style.current.padding width: appearanceView.contentWidth - 2 * Style.current.padding height: childrenRect.height - ButtonGroup { - id: chatModeSetting - } - - ButtonGroup { - id: appearanceSetting - } - Rectangle { id: preview anchors.top: parent.top @@ -128,41 +138,34 @@ SettingsContentBase { StatusQ.StatusLabeledSlider { id: zoomSlider - readonly property int initialValue: { - let scaleFactorStr = appearanceView.appearanceStore.readTextFile(uiScaleFilePath) - if (scaleFactorStr === "") { - return 100 - } - let scaleFactor = parseFloat(scaleFactorStr) - if (isNaN(scaleFactor)) { - return 100 - } - return scaleFactor * 100 - } + + readonly property int initialValue: priv.savedDpr * 100 + readonly property bool dirty: value !== initialValue + anchors.top: labelZoom.bottom anchors.topMargin: Style.current.padding width: parent.width from: 50 - to: 200 - stepSize: 50 - model: [ qsTr("50%"), qsTr("100%"), qsTr("150%"), qsTr("200%") ] + to: 300 + stepSize: 25 + model: [ qsTr("50%"), qsTr("75%"), qsTr("100%"), qsTr("125%"), qsTr("150%"), qsTr("175%"), qsTr("200%"), + qsTr("225%"), qsTr("250%"), qsTr("275%"), qsTr("300%")] value: initialValue - onValueChanged: { - if (value !== initialValue) { - appearanceView.appearanceStore.writeTextFile(uiScaleFilePath, value / 100.0) - } + onMoved: { + const uiScale = zoomSlider.value === 100 ? "" // reset to native highdpi + : zoomSlider.value / 100.0 + appearanceView.appearanceStore.writeTextFile(uiScaleFilePath, uiScale) } onPressedChanged: { - if (!pressed && value !== initialValue) { + if (!pressed && dirty) { confirmAppRestartModal.open() } } ConfirmAppRestartModal { id: confirmAppRestartModal - onClosed: { - zoomSlider.value = zoomSlider.initialValue - } + onAccepted: Utils.restartApplication(); + onClosed: zoomSlider.value = zoomSlider.initialValue } } diff --git a/ui/app/AppLayouts/Profile/views/LanguageView.qml b/ui/app/AppLayouts/Profile/views/LanguageView.qml index e7c80959fb..4deef60373 100644 --- a/ui/app/AppLayouts/Profile/views/LanguageView.qml +++ b/ui/app/AppLayouts/Profile/views/LanguageView.qml @@ -189,13 +189,12 @@ SettingsContentBase { sourceComponent: ConfirmationDialog { headerSettings.title: qsTr("Change language") confirmationText: qsTr("Display language has been changed. You must restart the application for changes to take effect.") - confirmButtonLabel: qsTr("Close the app now") + confirmButtonLabel: qsTr("Restart") onConfirmButtonClicked: { languageConfirmationDialog.active = false - Qt.quit() + Utils.restartApplication() } } } } } - diff --git a/ui/main.qml b/ui/main.qml index 9b57291385..32837003d7 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -1,11 +1,11 @@ -import QtQuick 2.13 -import QtQuick.Controls 2.13 -import QtQuick.Layouts 1.13 +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 import Qt.labs.platform 1.1 -import Qt.labs.settings 1.0 -import QtQuick.Window 2.12 -import QtQml 2.13 -import QtQuick.Controls.Universal 2.12 +import Qt.labs.settings 1.1 +import QtQuick.Window 2.15 +import QtQml 2.15 +import QtQuick.Controls.Universal 2.15 import utils 1.0 import shared 1.0 @@ -25,8 +25,8 @@ StatusWindow { id: applicationWindow objectName: "mainWindow" - minimumWidth: 1200 - minimumHeight: 680 + minimumWidth: 1200 / Screen.devicePixelRatio + minimumHeight: 680 / Screen.devicePixelRatio color: Style.current.background title: { // Set application settings diff --git a/vendor/DOtherSide/lib/src/DOtherSide.cpp b/vendor/DOtherSide/lib/src/DOtherSide.cpp index 13f3b808aa..a1936dd97f 100644 --- a/vendor/DOtherSide/lib/src/DOtherSide.cpp +++ b/vendor/DOtherSide/lib/src/DOtherSide.cpp @@ -166,8 +166,18 @@ void dos_qguiapplication_enable_hdpi(const char *uiScaleFilePath) QFile scaleFile(QString::fromUtf8(uiScaleFilePath)); if (scaleFile.open(QIODevice::ReadOnly)) { - const auto scale = scaleFile.readAll(); - qputenv("QT_SCALE_FACTOR", scale); + const auto scaleStr = scaleFile.readAll(); + bool ok = false; + const auto scale = scaleStr.toDouble(&ok); + if (ok) { + // we want to scale the app on our own + qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0"); + // workaround for bug/feature when Qt would bail out if the scale is "1" and revert to DPI based scaling + constexpr auto unaryScale = 1.1; + qputenv("QT_SCREEN_SCALE_FACTORS", QByteArray::number(unaryScale)); + // compensate for the workaround above so that we get the desired scale factor + qputenv("QT_SCALE_FACTOR", QByteArray::number(scale/unaryScale, 'f', 2)); + } } } @@ -373,7 +383,7 @@ void dos_qguiapplication_quit() void dos_qguiapplication_restart() { - QProcess::startDetached(QCoreApplication::applicationFilePath()); + QProcess::startDetached(QCoreApplication::applicationFilePath(), {}); dos_qguiapplication_quit(); }