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
This commit is contained in:
Lukáš Tinkl 2024-02-22 16:16:47 +01:00 committed by Lukáš Tinkl
parent 0497ecd82e
commit 630da7caaa
5 changed files with 75 additions and 81 deletions

View File

@ -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()
}
}
}
}

View File

@ -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
}
}

View File

@ -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()
}
}
}
}
}

View File

@ -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

View File

@ -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();
}