fix not thread-safe way for fetching settings singleton. remove qApp from Settings' parent, use nullptr replace it and leak it anyway. because we may initialize it before initializing QApplication. in that time, qApp is nullptr.
180 lines
5.6 KiB
C++
180 lines
5.6 KiB
C++
// SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com>
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "settings.h"
|
|
|
|
#include <QApplication>
|
|
#include <QStandardPaths>
|
|
#include <QDebug>
|
|
#include <QDir>
|
|
#include <QAction>
|
|
#include <QWidget>
|
|
#include <QKeySequence>
|
|
#include <QMetaEnum>
|
|
|
|
Settings *Settings::instance()
|
|
{
|
|
// SAFETY:
|
|
// This is a global singleton and it is leaked by design.
|
|
static Settings* INSTANCE = new Settings();
|
|
return INSTANCE;
|
|
}
|
|
|
|
namespace QEnumHelper
|
|
{
|
|
template <typename E>
|
|
E fromString(const QString &text, const E defaultValue)
|
|
{
|
|
bool ok;
|
|
E result = static_cast<E>(QMetaEnum::fromType<E>().keyToValue(text.toUtf8(), &ok));
|
|
if (!ok) {
|
|
return defaultValue;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <typename E>
|
|
QString toString(E value)
|
|
{
|
|
const int intValue = static_cast<int>(value);
|
|
return QString::fromUtf8(QMetaEnum::fromType<E>().valueToKey(intValue));
|
|
}
|
|
}
|
|
|
|
bool Settings::useLightCheckerboard() const
|
|
{
|
|
return m_qsettings->value("use_light_checkerboard", false).toBool();
|
|
}
|
|
|
|
bool Settings::loopGallery() const
|
|
{
|
|
return m_qsettings->value("loop_gallery", true).toBool();
|
|
}
|
|
|
|
bool Settings::svgTiny12Only() const
|
|
{
|
|
// Qt 6.7.0's SVG support is terrible caused by huge memory usage, see QTBUG-124287
|
|
// Qt 6.7.1's is somewhat better, memory issue seems fixed, but still laggy when zoom in, see QTBUG-126771.
|
|
// Qt 6.9.3 and Qt 6.10.1 seems no longer have the laggy issue, so let's make the default value different
|
|
// based on Qt version.
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 3)
|
|
return m_qsettings->value("svg_tiny12_only", true).toBool();
|
|
#else
|
|
return m_qsettings->value("svg_tiny12_only", false).toBool();
|
|
#endif // QT_VERSION < QT_VERSION_CHECK(6, 9, 3)
|
|
}
|
|
|
|
Settings::DoubleClickBehavior Settings::doubleClickBehavior() const
|
|
{
|
|
QString result = m_qsettings->value("double_click_behavior", "Close").toString();
|
|
|
|
return QEnumHelper::fromString<DoubleClickBehavior>(result, DoubleClickBehavior::Close);
|
|
}
|
|
|
|
Settings::MouseWheelBehavior Settings::mouseWheelBehavior() const
|
|
{
|
|
QString result = m_qsettings->value("mouse_wheel_behavior", "Zoom").toString();
|
|
|
|
return QEnumHelper::fromString<MouseWheelBehavior>(result, MouseWheelBehavior::Zoom);
|
|
}
|
|
|
|
Settings::WindowSizeBehavior Settings::initWindowSizeBehavior() const
|
|
{
|
|
QString result = m_qsettings->value("init_window_size_behavior", "Auto").toString();
|
|
|
|
return QEnumHelper::fromString<WindowSizeBehavior>(result, WindowSizeBehavior::Auto);
|
|
}
|
|
|
|
Qt::HighDpiScaleFactorRoundingPolicy Settings::hiDpiScaleFactorBehavior() const
|
|
{
|
|
QString result = m_qsettings->value("hidpi_scale_factor_behavior", "PassThrough").toString();
|
|
|
|
return QEnumHelper::fromString<Qt::HighDpiScaleFactorRoundingPolicy>(result, Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
}
|
|
|
|
void Settings::setUseLightCheckerboard(bool light)
|
|
{
|
|
m_qsettings->setValue("use_light_checkerboard", light);
|
|
m_qsettings->sync();
|
|
}
|
|
|
|
void Settings::setLoopGallery(bool on)
|
|
{
|
|
m_qsettings->setValue("loop_gallery", on);
|
|
m_qsettings->sync();
|
|
}
|
|
|
|
void Settings::setSvgTiny12Only(bool on)
|
|
{
|
|
m_qsettings->setValue("svg_tiny12_only", on);
|
|
m_qsettings->sync();
|
|
}
|
|
|
|
void Settings::setDoubleClickBehavior(DoubleClickBehavior dcb)
|
|
{
|
|
m_qsettings->setValue("double_click_behavior", QEnumHelper::toString(dcb));
|
|
m_qsettings->sync();
|
|
}
|
|
|
|
void Settings::setMouseWheelBehavior(MouseWheelBehavior mwb)
|
|
{
|
|
m_qsettings->setValue("mouse_wheel_behavior", QEnumHelper::toString(mwb));
|
|
m_qsettings->sync();
|
|
}
|
|
|
|
void Settings::setInitWindowSizeBehavior(WindowSizeBehavior wsb)
|
|
{
|
|
m_qsettings->setValue("init_window_size_behavior", QEnumHelper::toString(wsb));
|
|
m_qsettings->sync();
|
|
}
|
|
|
|
void Settings::setHiDpiScaleFactorBehavior(Qt::HighDpiScaleFactorRoundingPolicy hidpi)
|
|
{
|
|
m_qsettings->setValue("hidpi_scale_factor_behavior", QEnumHelper::toString(hidpi));
|
|
m_qsettings->sync();
|
|
}
|
|
|
|
#if defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN)
|
|
#include <windows.h>
|
|
// QCoreApplication::applicationDirPath() parses the "applicationDirPath" from arg0, which...
|
|
// 1. rely on a QApplication object instance
|
|
// but we need to call QGuiApplication::setHighDpiScaleFactorRoundingPolicy() before QApplication get created
|
|
// 2. arg0 is NOT garanteed to be the path of execution
|
|
// see also: https://stackoverflow.com/questions/383973/is-args0-guaranteed-to-be-the-path-of-execution
|
|
// This function is here mainly for #1.
|
|
QString getApplicationDirPath()
|
|
{
|
|
WCHAR buffer[MAX_PATH];
|
|
GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
|
QString appPath = QString::fromWCharArray(buffer);
|
|
|
|
return appPath.left(appPath.lastIndexOf('\\'));
|
|
}
|
|
#endif // defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN)
|
|
|
|
Settings::Settings(QObject *parent)
|
|
: QObject(parent)
|
|
{
|
|
QString configPath;
|
|
|
|
#if defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN)
|
|
QString portableConfigDirPath = QDir(getApplicationDirPath()).absoluteFilePath("data");
|
|
QFileInfo portableConfigDirInfo(portableConfigDirPath);
|
|
if (portableConfigDirInfo.exists() && portableConfigDirInfo.isDir() && portableConfigDirInfo.isWritable()) {
|
|
// we can use it.
|
|
configPath = portableConfigDirPath;
|
|
}
|
|
#endif // defined(FLAG_PORTABLE_MODE_SUPPORT) && defined(Q_OS_WIN)
|
|
|
|
if (configPath.isEmpty()) {
|
|
// Should be %LOCALAPPDATA%\<APPNAME> under Windows, ~/.config/<APPNAME> under Linux.
|
|
configPath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
|
|
}
|
|
|
|
m_qsettings = new QSettings(QDir(configPath).absoluteFilePath("config.ini"), QSettings::IniFormat, this);
|
|
|
|
qRegisterMetaType<QList<QKeySequence>>();
|
|
}
|
|
|