diff --git a/modules/juce_data_structures/values/juce_Value.cpp b/modules/juce_data_structures/values/juce_Value.cpp index 4da83a049a..0b2ee7dba9 100644 --- a/modules/juce_data_structures/values/juce_Value.cpp +++ b/modules/juce_data_structures/values/juce_Value.cpp @@ -27,72 +27,72 @@ class SharedValueSourceUpdater : public ReferenceCountedObject, private AsyncUpdater { public: - SharedValueSourceUpdater() : insideCallback (false) {} + SharedValueSourceUpdater() : sourcesBeingIterated (nullptr) {} + ~SharedValueSourceUpdater() { masterReference.clear(); } - typedef ReferenceCountedObjectPtr Ptr; - - void update (Value::ValueSource* source) + void update (Value::ValueSource* const source) { - sourcesToUpdate.add (source); + sourcesNeedingAnUpdate.add (source); - if (! insideCallback) + if (sourcesBeingIterated == nullptr) triggerAsyncUpdate(); } - static SharedValueSourceUpdater* getOrCreateSharedUpdater() + void valueDeleted (Value::ValueSource* const source) { - Ptr& p = getSharedUpdater(); - - if (p == nullptr) - p = new SharedValueSourceUpdater(); + sourcesNeedingAnUpdate.removeValue (source); - return p; + if (sourcesBeingIterated != nullptr) + sourcesBeingIterated->removeValue (source); } - static void releaseIfUnused() - { - if (Ptr& p = getSharedUpdater()) - if (p->getReferenceCount() == 1) - p = nullptr; - } + WeakReference::Master masterReference; private: - ReferenceCountedArray sourcesToUpdate; - bool insideCallback; - - static Ptr& getSharedUpdater() - { - static Ptr updater; - return updater; - } + typedef SortedSet SourceSet; + SourceSet sourcesNeedingAnUpdate; + SourceSet* sourcesBeingIterated; void handleAsyncUpdate() { - int maxLoops = 10; - const ScopedValueSetter inside (insideCallback, true, false); - const Ptr localRef (this); + const ReferenceCountedObjectPtr localRef (this); - while (sourcesToUpdate.size() > 0 && --maxLoops >= 0) { - ReferenceCountedArray sources; - sources.swapWithArray (sourcesToUpdate); - - for (int i = 0; i < sources.size(); ++i) - sources.getObjectPointerUnchecked(i)->sendChangeMessage (true); + const ScopedValueSetter inside (sourcesBeingIterated, nullptr, nullptr); + int maxLoops = 10; + + while (sourcesNeedingAnUpdate.size() > 0) + { + if (--maxLoops == 0) + { + triggerAsyncUpdate(); + break; + } + + SourceSet sources; + sources.swapWith (sourcesNeedingAnUpdate); + sourcesBeingIterated = &sources; + + for (int i = sources.size(); --i >= 0;) + if (i < sources.size()) + sources.getUnchecked(i)->sendChangeMessage (true); + } } } - JUCE_DECLARE_NON_COPYABLE (SharedValueSourceUpdater); + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedValueSourceUpdater); }; +static WeakReference sharedUpdater; + Value::ValueSource::ValueSource() { } Value::ValueSource::~ValueSource() { - asyncUpdater = nullptr; - SharedValueSourceUpdater::releaseIfUnused(); + if (asyncUpdater != nullptr) + static_cast (asyncUpdater.get())->valueDeleted (this); } void Value::ValueSource::sendChangeMessage (const bool synchronous) @@ -103,17 +103,30 @@ void Value::ValueSource::sendChangeMessage (const bool synchronous) { if (synchronous) { - asyncUpdater = nullptr; const ReferenceCountedObjectPtr localRef (this); + asyncUpdater = nullptr; for (int i = numListeners; --i >= 0;) if (Value* const v = valuesWithListeners[i]) v->callListeners(); } - else if (asyncUpdater == nullptr) + else { - SharedValueSourceUpdater* const updater = SharedValueSourceUpdater::getOrCreateSharedUpdater(); - asyncUpdater = updater; + SharedValueSourceUpdater* updater = static_cast (asyncUpdater.get()); + + if (updater == nullptr) + { + if (sharedUpdater == nullptr) + { + asyncUpdater = updater = new SharedValueSourceUpdater(); + sharedUpdater = updater; + } + else + { + asyncUpdater = updater = sharedUpdater.get(); + } + } + updater->update (this); } } @@ -279,8 +292,11 @@ void Value::removeListener (ValueListener* const listener) void Value::callListeners() { - Value v (*this); // (create a copy in case this gets deleted by a callback) - listeners.call (&ValueListener::valueChanged, v); + if (listeners.size() > 0) + { + Value v (*this); // (create a copy in case this gets deleted by a callback) + listeners.call (&ValueListener::valueChanged, v); + } } OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const Value& value) diff --git a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp index f5fea44397..010f1f056d 100644 --- a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp +++ b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp @@ -822,7 +822,7 @@ private: //============================================================================== class TextEditor::TextHolderComponent : public Component, public Timer, - private ValueListener + public ValueListener { public: TextHolderComponent (TextEditor& ed) : owner (ed) @@ -962,6 +962,7 @@ TextEditor::~TextEditor() if (ComponentPeer* const peer = getPeer()) peer->dismissPendingTextInput(); + textValue.removeListener (textHolder); textValue.referTo (Value()); clearInternal (0); viewport = nullptr;