diff options
Diffstat (limited to 'options')
-rw-r--r-- | options/base-value.cpp | 19 | ||||
-rw-r--r-- | options/base-value.hpp | 7 | ||||
-rw-r--r-- | options/bundle.hpp | 9 | ||||
-rw-r--r-- | options/connector.cpp | 6 | ||||
-rw-r--r-- | options/connector.hpp | 4 | ||||
-rw-r--r-- | options/defs.hpp | 2 | ||||
-rw-r--r-- | options/globals.cpp | 22 | ||||
-rw-r--r-- | options/globals.hpp | 6 | ||||
-rw-r--r-- | options/group.hpp | 2 | ||||
-rw-r--r-- | options/lang/de_DE.ts | 4 | ||||
-rw-r--r-- | options/lang/zh_CN.ts | 2 | ||||
-rw-r--r-- | options/metatype.cpp | 2 | ||||
-rw-r--r-- | options/scoped.cpp | 9 | ||||
-rw-r--r-- | options/scoped.hpp | 4 | ||||
-rw-r--r-- | options/slider.hpp | 1 | ||||
-rw-r--r-- | options/tie.cpp | 33 | ||||
-rw-r--r-- | options/tie.hpp | 28 | ||||
-rw-r--r-- | options/value-traits.hpp | 81 | ||||
-rw-r--r-- | options/value.hpp | 44 |
19 files changed, 186 insertions, 99 deletions
diff --git a/options/base-value.cpp b/options/base-value.cpp index d4ec4b6c..950629d0 100644 --- a/options/base-value.cpp +++ b/options/base-value.cpp @@ -1,7 +1,20 @@ #include "base-value.hpp" +#include <QThread> using namespace options; +//#define OTR_TRACE_NOTIFY + +const bool value_::TRACE_NOTIFY = +#ifdef OTR_TRACE_NOTIFY + true; +#else + [] { + auto b = qgetenv("OTR_TRACE_NOTIFY"); + return !b.isEmpty() && b != "0"; + }(); +#endif + value_::value_(bundle const& b, const QString& name) noexcept : b(b), self_name(name) { @@ -12,3 +25,9 @@ value_::~value_() { b->on_value_destructed(this); } + +void value_::maybe_trace(const char* str) const +{ + if (TRACE_NOTIFY) + qDebug().noquote() << str << QThread::currentThreadId() << b->name() << self_name << get_variant(); +} diff --git a/options/base-value.hpp b/options/base-value.hpp index 722107a4..5317191b 100644 --- a/options/base-value.hpp +++ b/options/base-value.hpp @@ -6,7 +6,6 @@ #include "metatype.hpp" #include "export.hpp" -#include "compat/macros.hpp" #include "value-traits.hpp" #include <utility> @@ -26,6 +25,7 @@ class OTR_OPTIONS_EXPORT value_ : public QObject { Q_OBJECT + template<typename t> using cv_qualified = detail::cv_qualified<t>; template<typename t> using signal_sig = void(value_::*)(cv_qualified<t>) const; @@ -40,6 +40,8 @@ public: return static_cast<signal_sig<t>>(&value_::valueChanged); } + static const bool TRACE_NOTIFY; + signals: OTR_OPTIONS_SIGNAL(double); OTR_OPTIONS_SIGNAL(float); @@ -65,6 +67,8 @@ protected: virtual void store_variant(QVariant&&) noexcept = 0; virtual void store_variant(const QVariant&) noexcept = 0; + void maybe_trace(const char* str) const; + template<typename t> void store_(const t& datum) { @@ -91,6 +95,7 @@ public slots: virtual void set_to_default() noexcept = 0; virtual void notify() const = 0; + virtual void notify_() const = 0; virtual QVariant get_variant() const noexcept = 0; }; diff --git a/options/bundle.hpp b/options/bundle.hpp index 158fcef9..c97eeff2 100644 --- a/options/bundle.hpp +++ b/options/bundle.hpp @@ -21,7 +21,7 @@ #include <QObject> #include <QString> #include <QVariant> -#include <QMutex> +#include <QRecursiveMutex> #include <QDebug> @@ -46,7 +46,7 @@ class OTR_OPTIONS_EXPORT bundle final : public QObject, public connector friend struct bundler; - mutable QMutex mtx { QMutex::Recursive }; + mutable QRecursiveMutex mtx; const QString group_name; group saved; group transient; @@ -62,7 +62,7 @@ public: bundle(const bundle&) = delete; bundle& operator=(const bundle&) = delete; - QMutex* get_mtx() const override { return &mtx; } + QRecursiveMutex* get_mtx() const override { return &mtx; } QString name() const { return group_name; } explicit bundle(const QString& group_name); @@ -93,7 +93,7 @@ struct OTR_OPTIONS_EXPORT bundler final static void reload(); private: - QMutex implsgl_mtx { QMutex::Recursive }; + QRecursiveMutex implsgl_mtx; std::unordered_map<k, weak> implsgl_data {}; void notify_(); @@ -114,4 +114,3 @@ private: void set_value_to_default(value_* val); } // ns options::detail - diff --git a/options/connector.cpp b/options/connector.cpp index 40c99a82..e86958f7 100644 --- a/options/connector.cpp +++ b/options/connector.cpp @@ -64,6 +64,8 @@ void connector::on_value_created(value_type val) void connector::notify_values(const QString& name) const { + QMutexLocker l(get_mtx()); + auto it = connected_values.find(name); if (it != connected_values.cend()) for (value_type val : it->second) @@ -72,6 +74,8 @@ void connector::notify_values(const QString& name) const void connector::notify_all_values() const { + QMutexLocker l(get_mtx()); + for (const auto& [k, v] : connected_values) for (value_type val : v) val->notify(); @@ -79,6 +83,8 @@ void connector::notify_all_values() const void connector::set_all_to_default_() { + QMutexLocker l(get_mtx()); + for (auto& pair : connected_values) for (auto& val : pair.second) val->set_to_default(); diff --git a/options/connector.hpp b/options/connector.hpp index 025efda2..bcac5676 100644 --- a/options/connector.hpp +++ b/options/connector.hpp @@ -14,7 +14,7 @@ #include <vector> #include <QString> -#include <QMutex> +#include <QRecursiveMutex> #include "export.hpp" @@ -38,7 +38,7 @@ class OTR_OPTIONS_EXPORT connector protected: void notify_values(const QString& name) const; void notify_all_values() const; - virtual QMutex* get_mtx() const = 0; + virtual QRecursiveMutex* get_mtx() const = 0; void set_all_to_default_(); public: diff --git a/options/defs.hpp b/options/defs.hpp index 9ea4f3b3..797a8fda 100644 --- a/options/defs.hpp +++ b/options/defs.hpp @@ -2,5 +2,3 @@ #define OPENTRACK_PROFILE_FILENAME_KEY "settings-filename" #define OPENTRACK_DEFAULT_PROFILE "default.ini" - - diff --git a/options/globals.cpp b/options/globals.cpp index 386ef56d..39eb6014 100644 --- a/options/globals.cpp +++ b/options/globals.cpp @@ -1,10 +1,13 @@ #include "globals.hpp" #include "compat/base-path.hpp" #include "defs.hpp" +#include "opentrack-org.hxx" #include <QFile> +#include <QFileInfo> #include <QDir> #include <QStandardPaths> +#include <QDateTime> #include <QDebug> namespace options::globals::detail { @@ -124,9 +127,24 @@ QString ini_combine(const QString& filename) QStringList ini_list() { - QDir settings_dir(ini_directory()); + static QMutex mtx; + static QStringList list; + QMutexLocker l{&mtx}; + + const QString dirname = ini_directory(); + + { + static QDateTime last_time = {}; + auto time = QFileInfo{dirname}.lastModified(); + if (time == last_time) + return list; + last_time = time; + } + + QDir settings_dir(dirname); + using f = QDir::Filter; - auto list = settings_dir.entryList({ QStringLiteral("*.ini") }, f::Files | f::Readable, QDir::Name); + list = settings_dir.entryList({ QStringLiteral("*.ini") }, f::Files | f::Readable, QDir::Name); std::sort(list.begin(), list.end()); return list; } diff --git a/options/globals.hpp b/options/globals.hpp index 7af6533d..1a92cc47 100644 --- a/options/globals.hpp +++ b/options/globals.hpp @@ -1,13 +1,13 @@ #pragma once #include "export.hpp" -#include "compat/macros.hpp" +#include "compat/macros.h" #include <optional> #include <QString> #include <QSettings> -#include <QMutex> +#include <QRecursiveMutex> namespace options::globals::detail { @@ -17,7 +17,7 @@ struct OTR_OPTIONS_EXPORT ini_ctx { std::optional<QSettings> qsettings { std::in_place }; QString pathname; - QMutex mtx { QMutex::Recursive }; + QRecursiveMutex mtx; unsigned refcount = 0; bool modifiedp = false; diff --git a/options/group.hpp b/options/group.hpp index 93299b6e..11bab965 100644 --- a/options/group.hpp +++ b/options/group.hpp @@ -4,7 +4,7 @@ #include "compat/base-path.hpp" #include "compat/library-path.hpp" -#include "compat/macros.hpp" +#include "compat/macros.h" #include "compat/qhash.hpp" #include "export.hpp" diff --git a/options/lang/de_DE.ts b/options/lang/de_DE.ts new file mode 100644 index 00000000..1552582e --- /dev/null +++ b/options/lang/de_DE.ts @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1" language="de_DE"> +</TS> diff --git a/options/lang/zh_CN.ts b/options/lang/zh_CN.ts index 6401616d..e5ca8aa9 100644 --- a/options/lang/zh_CN.ts +++ b/options/lang/zh_CN.ts @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> -<TS version="2.1"> +<TS version="2.1" language="zh_CN"> </TS> diff --git a/options/metatype.cpp b/options/metatype.cpp index 7962b81b..f85429e0 100644 --- a/options/metatype.cpp +++ b/options/metatype.cpp @@ -1,5 +1,4 @@ #include <QMetaType> -#include "compat/macros.hpp" namespace options::detail { @@ -7,7 +6,6 @@ template<typename t> void declare_metatype_for_type(const char* str) { qRegisterMetaType<t>(str); - qRegisterMetaTypeStreamOperators<t>(); } } // ns options::detail diff --git a/options/scoped.cpp b/options/scoped.cpp index f5e219e2..33db7907 100644 --- a/options/scoped.cpp +++ b/options/scoped.cpp @@ -1,4 +1,5 @@ #include "scoped.hpp" +#include "compat/run-in-thread.hpp" #include <QApplication> #include <QThread> @@ -47,8 +48,14 @@ static bool is_tracker_teardown() opts::~opts() { - if (!is_tracker_teardown()) + // XXX TODO debug crash with ps3eye dialog in pt tracker -sh 20211019 + if (!is_tracker_teardown() && raii) +#if 1 + run_in_thread_sync(qApp->thread(), [this]{ b->reload(); }); +#else + assert(b); b->reload(); +#endif #if 0 else qDebug() << "in teardown, not reloading" << b->name(); diff --git a/options/scoped.hpp b/options/scoped.hpp index dd7dbacf..81e6bd19 100644 --- a/options/scoped.hpp +++ b/options/scoped.hpp @@ -27,9 +27,13 @@ struct OTR_OPTIONS_EXPORT opts opts& operator=(const opts&) = delete; opts(const opts&) = delete; + void set_raii_dtor_state(bool x) { raii = x; } + protected: explicit opts(const QString& name); ~opts(); +private: + bool raii = true; }; } diff --git a/options/slider.hpp b/options/slider.hpp index 5d21bf0f..1e721ae0 100644 --- a/options/slider.hpp +++ b/options/slider.hpp @@ -8,7 +8,6 @@ #pragma once #include "export.hpp" -#include "compat/macros.hpp" #include <type_traits> diff --git a/options/tie.cpp b/options/tie.cpp index 43e6c596..adf26b53 100644 --- a/options/tie.cpp +++ b/options/tie.cpp @@ -8,7 +8,7 @@ #include "tie.hpp" #include "compat/run-in-thread.hpp" -#include "compat/macros.hpp" +#include "compat/macros.h" #include "value-traits.hpp" @@ -28,8 +28,12 @@ void tie_setting(value<QString>& v, QComboBox* cb) { cb->setCurrentText(v); v = cb->currentText(); - value_::connect(cb, SIGNAL(currentTextChanged(QString)), &v, SLOT(setValue(const QString&)), v.DIRECT_CONNTYPE); - value_::connect(&v, SIGNAL(valueChanged(const QString&)), cb, SLOT(setCurrentText(const QString&)), v.SAFE_CONNTYPE); + auto set_current_text = [cb, &v](const QString& str) { + cb->setCurrentText(str); + v = cb->currentText(); + }; + value_::connect(cb, &QComboBox::currentTextChanged, &v, v.value_changed<QString>(), v.DIRECT_CONNTYPE); + value_::connect(&v, v.value_changed<QString>(), cb, set_current_text, v.SAFE_CONNTYPE); } void tie_setting(value<QVariant>& v, QComboBox* cb) @@ -39,13 +43,10 @@ void tie_setting(value<QVariant>& v, QComboBox* cb) int idx = -1; for (int k = 0; k < sz; k++) - { - if (cb->itemData(k) == var) - { + if (cb->itemData(k) == var) { idx = k; break; } - } cb->setCurrentIndex(idx); return idx; }; @@ -58,16 +59,11 @@ void tie_setting(value<QVariant>& v, QComboBox* cb) v = {}; value_::connect(cb, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), - &v, [cb, &v](int idx) { - v = cb->itemData(idx); - }, v.DIRECT_CONNTYPE); + &v, [cb, &v](int idx) { v = cb->itemData(idx); }, + v.DIRECT_CONNTYPE); value_::connect(&v, value_::value_changed<QVariant>(), - cb, - [cb, set_idx](const QVariant& var) { - run_in_thread_sync(cb, [&] { - set_idx(var); - }); - }, v.DIRECT_CONNTYPE); + cb, [set_idx](const QVariant& var) { set_idx(var); }, + v.SAFE_CONNTYPE); } void tie_setting(value<bool>& v, QRadioButton* cb) @@ -128,10 +124,7 @@ void tie_setting(value<slider_value>& v, QSlider* w) v = v().update_from_slider(w->value(), q_min, q_max); } - value_::connect(w, - &QSlider::valueChanged, - &v, - [=, &v](int pos) + value_::connect(w, &QSlider::valueChanged, &v, [=, &v](int pos) { run_in_thread_sync(w, [&]() { diff --git a/options/tie.hpp b/options/tie.hpp index 2ac27d64..194a3a5d 100644 --- a/options/tie.hpp +++ b/options/tie.hpp @@ -38,16 +38,12 @@ std::enable_if_t<std::is_enum_v<t>> tie_setting(value<t>& v, QComboBox* cb) v = static_cast<t>(cb->currentData().toInt()); value_::connect(cb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), - &v, [&v, cb](int idx) { - run_in_thread_sync(cb, [&] { - v = static_cast<t>(cb->itemData(idx).toInt()); - }); - }, v.DIRECT_CONNTYPE); + &v, [&v, cb](int idx) { v = static_cast<t>(cb->itemData(idx).toInt()); }, + v.DIRECT_CONNTYPE); value_::connect(&v, value_::value_changed<int>(), - cb, [cb](int x) { - run_in_thread_sync(cb, [=] { cb->setCurrentIndex(cb->findData(x)); }); - }, v.DIRECT_CONNTYPE); + cb, [cb](int x) { cb->setCurrentIndex(cb->findData(x)); }, + v.SAFE_CONNTYPE); } template<typename t, typename From, typename To> @@ -57,23 +53,17 @@ void tie_setting(value<t>& v, QComboBox* cb, From&& fn_to_index, To&& fn_to_valu v = fn_to_value(cb->currentIndex(), cb->currentData()); value_::connect(cb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), - &v, [&v, cb, fn_to_value](int idx) { - run_in_thread_sync(cb, [&] { - v = fn_to_value(idx, cb->currentData()); - }); - }, v.DIRECT_CONNTYPE); + &v, [&v, cb, fn_to_value](int idx) { v = fn_to_value(idx, cb->currentData()); }, + v.DIRECT_CONNTYPE); value_::connect(&v, value_::value_changed<t>(), - cb, [cb, fn_to_index](cv_qualified<t>& v) { - run_in_thread_sync(cb, [&] { - cb->setCurrentIndex(fn_to_index(v)); - }); - }, v.DIRECT_CONNTYPE); + cb, [cb, fn_to_index](detail::cv_qualified<t>& v) { cb->setCurrentIndex(fn_to_index(v)); }, + v.SAFE_CONNTYPE); } template<typename t, typename F> void tie_setting(value<t>& v, QLabel* lb, F&& fun) { - auto closure = [lb, fun](cv_qualified<t> v) { lb->setText(fun(v)); }; + auto closure = [lb, fun](detail::cv_qualified<t> v) { lb->setText(fun(v)); }; closure(v()); value_::connect(&v, value_::value_changed<t>(), diff --git a/options/value-traits.hpp b/options/value-traits.hpp index aeb34cfa..145cd924 100644 --- a/options/value-traits.hpp +++ b/options/value-traits.hpp @@ -9,97 +9,110 @@ #include <QString> namespace options::detail { - -template<typename t, typename Enable = void> -struct value_traits; +template<typename t> +using cv_qualified = + std::conditional_t<std::is_fundamental_v<std::remove_cvref_t<t>>, + std::remove_cvref_t<t>, + std::add_lvalue_reference_t<std::add_const_t<std::remove_cvref_t<t>>>>; template<typename t, typename u = t, typename Enable = void> struct default_value_traits { using value_type = t; using stored_type = u; - using self = value_traits<value_type>; - static value_type value_with_default(const value_type& val, const value_type&) + static inline + value_type value_with_default(cv_qualified<value_type> val, cv_qualified<value_type>) { return val; } - static value_type value_from_storage(const stored_type& x) + static inline + value_type value_from_storage(cv_qualified<stored_type> x) { return static_cast<value_type>(x); } - static stored_type storage_from_value(const value_type& val) + static inline + stored_type storage_from_value(cv_qualified<value_type> val) { return static_cast<stored_type>(val); } - static value_type value_from_qvariant(const QVariant& x) + static inline + value_type value_from_qvariant(const QVariant& x) { - return self::value_from_storage(self::storage_from_qvariant(x)); + return value_from_storage(storage_from_qvariant(x)); } - static QVariant qvariant_from_value(const value_type& val) + static inline + QVariant qvariant_from_value(cv_qualified<value_type> val) { - return self::qvariant_from_storage(self::storage_from_value(val)); + return qvariant_from_storage(storage_from_value(val)); } - static constexpr value_type pass_value(const value_type& x) + static constexpr inline + value_type pass_value(cv_qualified<value_type> x) { if constexpr(std::is_same_v<value_type, stored_type>) return x; else - return self::value_from_storage(self::storage_from_value(x)); + return value_from_storage(storage_from_value(x)); } - static stored_type storage_from_qvariant(const QVariant& x) + static inline + stored_type storage_from_qvariant(const QVariant& x) { // XXX TODO return x.value<stored_type>(); } - static QVariant qvariant_from_storage(const stored_type& val) + static inline + QVariant qvariant_from_storage(cv_qualified<stored_type> val) { // XXX TODO return QVariant::fromValue<stored_type>(val); } - static bool is_equal(const value_type& x, const value_type& y) + static inline + bool is_equal(cv_qualified<value_type> x, cv_qualified<value_type> y) { return x == y; } }; -template<typename t, typename Enable> +template<typename t, typename Enable = void> struct value_traits : default_value_traits<t> {}; template<> -struct value_traits<double> : default_value_traits<double> +inline +bool default_value_traits<double>::is_equal(double x, double y) { - static bool is_equal(value_type x, value_type y) { return std::fabs(x - y) < 1e-6; } -}; + return std::fabs(x - y) < 1e-6; +} + +template<> struct value_traits<float, double> : default_value_traits<float> {}; template<> -struct value_traits<float> : default_value_traits<float> +inline +bool default_value_traits<float, double>::is_equal(float x, float y) { - static bool is_equal(value_type x, value_type y) { return std::fabs(x - y) < 1e-6f; } -}; + return std::fabs(x - y) < 1e-6f; +} template<> -struct value_traits<slider_value> : default_value_traits<slider_value> +inline +slider_value default_value_traits<slider_value>::value_with_default(cv_qualified<slider_value> val, cv_qualified<slider_value> def) { - static slider_value value_with_default(const slider_value& val, const slider_value& def) - { - return { val.cur(), def.min(), def.max() }; - } + return { val.cur(), def.min(), def.max() }; +} - static bool is_equal(const slider_value& x, const slider_value& y) - { - using tr = value_traits<double>; - return tr::is_equal(x.cur(), y.cur()); - } -}; +template<> +inline +bool default_value_traits<slider_value>::is_equal(cv_qualified<slider_value> x, cv_qualified<slider_value> y) +{ + return value_traits<double>::is_equal(x.cur(), y.cur()); +} // Qt uses int a lot in slots so use it for all enums template<typename t> diff --git a/options/value.hpp b/options/value.hpp index 92e2878f..9a7487b8 100644 --- a/options/value.hpp +++ b/options/value.hpp @@ -14,7 +14,6 @@ #include "slider.hpp" #include "base-value.hpp" #include "value-traits.hpp" -#include "compat/macros.hpp" #include <type_traits> #include <utility> @@ -38,8 +37,10 @@ namespace options { template<typename t> class value final : public value_ { - static_assert(std::is_same_v<t, remove_cvref_t<t>>); + static_assert(std::is_same_v<t, std::remove_cvref_t<t>>); + mutable QMutex mtx; const t def; + mutable t cached_value; using traits = detail::value_traits<t>; never_inline @@ -92,10 +93,42 @@ public: return traits::qvariant_from_value(def); } + never_inline + void notify_() const override + { + auto x = get(); + { + QMutexLocker l(&mtx); + cached_value = x; + } + maybe_trace("notify +"); + emit valueChanged(traits::storage_from_value(x)); + maybe_trace("notify -"); + } + + never_inline void notify() const override { - if (!is_null()) - emit valueChanged(traits::storage_from_value(get())); + if (is_null()) + return; + + auto x = get(); + { + QMutexLocker l(&mtx); + if (traits::is_equal(x, cached_value)) + { + //maybe_trace("notify ~"); + return; + } + else + { + cached_value = x; + l.unlock(); + maybe_trace("notify +"); + emit valueChanged(traits::storage_from_value(x)); + maybe_trace("notify -"); + } + } } auto& operator=(t&& datum) noexcept @@ -104,6 +137,7 @@ public: return *this; store_variant(traits::qvariant_from_value(traits::pass_value(datum))); + maybe_trace("set-value"); return *this; } @@ -126,7 +160,7 @@ public: static constexpr Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; static constexpr Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; - value(bundle b, const QString& name, t def) noexcept : value_(b, name), def(std::move(def)) + value(bundle b, const QString& name, t def) noexcept : value_(b, name), def(std::move(def)), cached_value{get()} { } |