summaryrefslogtreecommitdiffhomepage
path: root/options
diff options
context:
space:
mode:
Diffstat (limited to 'options')
-rw-r--r--options/base-value.cpp19
-rw-r--r--options/base-value.hpp7
-rw-r--r--options/bundle.hpp9
-rw-r--r--options/connector.cpp6
-rw-r--r--options/connector.hpp4
-rw-r--r--options/defs.hpp2
-rw-r--r--options/globals.cpp22
-rw-r--r--options/globals.hpp6
-rw-r--r--options/group.hpp2
-rw-r--r--options/lang/de_DE.ts4
-rw-r--r--options/lang/zh_CN.ts2
-rw-r--r--options/metatype.cpp2
-rw-r--r--options/scoped.cpp9
-rw-r--r--options/scoped.hpp4
-rw-r--r--options/slider.hpp1
-rw-r--r--options/tie.cpp33
-rw-r--r--options/tie.hpp28
-rw-r--r--options/value-traits.hpp81
-rw-r--r--options/value.hpp44
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()}
{
}