X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fchange_signaller.h;h=1d7d482df2539d8c989609e4cf162a323ceb7bfd;hb=0f11f0c25465464b28db713cccd37d7d8de483e1;hp=74965fc3e316646082a0563e2b68e7cafa868261;hpb=e0255a64d22440d718e5512f34a4f21f0d37a21b;p=dcpomatic.git diff --git a/src/lib/change_signaller.h b/src/lib/change_signaller.h index 74965fc3e..1d7d482df 100644 --- a/src/lib/change_signaller.h +++ b/src/lib/change_signaller.h @@ -23,6 +23,10 @@ #define DCPOMATIC_CHANGE_SIGNALLER_H +#include +#include + + enum class ChangeType { PENDING, @@ -31,30 +35,104 @@ enum class ChangeType }; +template +class ChangeSignal +{ +public: + ChangeSignal(T* thing_, P property_, ChangeType type_) + : thing(thing_) + , property(property_) + , type(type_) + {} + + T* thing; + P property; + ChangeType type; +}; + + +class ChangeSignalDespatcherBase +{ +protected: + static boost::mutex _instance_mutex; +}; + + +template +class ChangeSignalDespatcher : public ChangeSignalDespatcherBase +{ +public: + ChangeSignalDespatcher() = default; + + ChangeSignalDespatcher(ChangeSignalDespatcher const&) = delete; + ChangeSignalDespatcher& operator=(ChangeSignalDespatcher const&) = delete; + + void signal_change(ChangeSignal const& signal) + { + if (_suspended) { + boost::mutex::scoped_lock lm(_mutex); + _pending.push_back(signal); + } else { + signal.thing->signal_change(signal.type, signal.property); + } + } + + void suspend() + { + boost::mutex::scoped_lock lm(_mutex); + _suspended = true; + } + + void resume() + { + boost::mutex::scoped_lock lm(_mutex); + auto pending = _pending; + lm.unlock(); + + for (auto signal: pending) { + signal.thing->signal_change(signal.type, signal.property); + } + + lm.lock(); + _pending.clear(); + _suspended = false; + } + + static ChangeSignalDespatcher* instance() + { + static boost::mutex _instance_mutex; + static boost::mutex::scoped_lock lm(_instance_mutex); + static ChangeSignalDespatcher* _instance; + if (!_instance) { + _instance = new ChangeSignalDespatcher(); + } + return _instance; + } + +private: + std::vector> _pending; + bool _suspended = false; + boost::mutex _mutex; +}; + + template class ChangeSignaller { public: ChangeSignaller (T* t, P p) - : _thing (t) - , _property (p) - , _done (true) + : _thing(t) + , _property(p) + , _done(true) { - _thing->signal_change (ChangeType::PENDING, _property); + ChangeSignalDespatcher::instance()->signal_change({_thing, _property, ChangeType::PENDING}); } ~ChangeSignaller () { - if (_done) { - _thing->signal_change (ChangeType::DONE, _property); - } else { - _thing->signal_change (ChangeType::CANCELLED, _property); - } + ChangeSignalDespatcher::instance()->signal_change({_thing, _property, _done ? ChangeType::DONE : ChangeType::CANCELLED}); } - ChangeSignaller (ChangeSignaller const&) = delete; - ChangeSignaller& operator== (ChangeSignaller const&) = delete; - void abort () { _done = false;