andrewm@0: /* andrewm@0: TouchKeys: multi-touch musical keyboard control software andrewm@0: Copyright (c) 2013 Andrew McPherson andrewm@0: andrewm@0: This program is free software: you can redistribute it and/or modify andrewm@0: it under the terms of the GNU General Public License as published by andrewm@0: the Free Software Foundation, either version 3 of the License, or andrewm@0: (at your option) any later version. andrewm@0: andrewm@0: This program is distributed in the hope that it will be useful, andrewm@0: but WITHOUT ANY WARRANTY; without even the implied warranty of andrewm@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrewm@0: GNU General Public License for more details. andrewm@0: andrewm@0: You should have received a copy of the GNU General Public License andrewm@0: along with this program. If not, see . andrewm@0: andrewm@0: ===================================================================== andrewm@0: andrewm@0: Trigger.h: interface for objects to notify one another that new data andrewm@0: has arrived. TriggerSource can send triggers to any object inheriting andrewm@0: from TriggerDestination. Methods of keeping sources and destinations andrewm@0: in sync are included in each class. andrewm@0: */ andrewm@0: andrewm@0: #ifndef KEYCONTROL_TRIGGER_H andrewm@0: #define KEYCONTROL_TRIGGER_H andrewm@0: andrewm@0: #include andrewm@0: #include andrewm@0: #include "../JuceLibraryCode/JuceHeader.h" andrewm@0: #include "Types.h" andrewm@0: andrewm@0: class TriggerDestination; andrewm@0: andrewm@0: /* andrewm@0: * TriggerSource andrewm@0: * andrewm@0: * Provides a set of routines for an object that sends triggers with an associated timestamp. All Node andrewm@0: * objects inherit from Trigger, but other objects may use these routines as well. andrewm@0: */ andrewm@0: andrewm@0: class TriggerSource { andrewm@0: friend class TriggerDestination; andrewm@0: protected: andrewm@0: // Send a trigger event out to all our registered listeners. The type of the accompanying andrewm@0: // data will be set by the template of the subclass. andrewm@0: void sendTrigger(timestamp_type timestamp); andrewm@0: andrewm@0: public: andrewm@0: // ***** Constructor ***** andrewm@0: andrewm@0: TriggerSource() {} // No instantiating this class directly! andrewm@0: andrewm@0: // ***** Destructor ***** andrewm@0: andrewm@0: ~TriggerSource() { clearTriggerDestinations(); } andrewm@0: andrewm@0: // ***** Connection Management ***** andrewm@0: andrewm@0: bool hasTriggerDestinations() { return triggerDestinations_.size() > 0; } andrewm@0: andrewm@0: private: andrewm@0: // For internal use or use by friend class NodeBase only andrewm@0: andrewm@0: // These methods manage the list of objects to whom the triggers should be sent. All objects andrewm@0: // will inherit from the Triggerable base class. These shouldn't be called by the user directly; andrewm@0: // rather, they're called by Triggerable when it registers itself. andrewm@0: andrewm@0: void addTriggerDestination(TriggerDestination* dest); andrewm@0: void removeTriggerDestination(TriggerDestination* dest); andrewm@0: void clearTriggerDestinations(); andrewm@0: andrewm@0: // When sources are added or removed, they are first stored in separate locations to be updated andrewm@0: // prior to each new call of sendTrigger(). This way, destinations which are updated from functions andrewm@0: // called from sendTrigger() do not render the set inconsistent in the middle. andrewm@0: void processAddRemoveQueue(); andrewm@0: andrewm@0: private: andrewm@0: std::set triggerDestinations_; andrewm@0: std::set triggersToAdd_; andrewm@0: std::set triggersToRemove_; andrewm@0: bool triggerDestinationsModified_; andrewm@0: CriticalSection triggerSourceMutex_; andrewm@0: }; andrewm@0: andrewm@0: /* andrewm@0: * TriggerDestination andrewm@0: * andrewm@0: * This class accepts a Trigger event. Designed to be inherited by more complex objects. andrewm@0: */ andrewm@0: andrewm@0: class TriggerDestination { andrewm@0: friend class TriggerSource; andrewm@0: public: andrewm@0: // ***** Constructors ***** andrewm@0: andrewm@0: TriggerDestination() {} andrewm@0: TriggerDestination(TriggerDestination const& obj) : registeredTriggerSources_(obj.registeredTriggerSources_) {} andrewm@0: andrewm@0: // This defines what we actually do when a trigger is received. It should be implemented andrewm@0: // by the subclass. andrewm@0: virtual void triggerReceived(TriggerSource* who, timestamp_type timestamp) { /*std::cout << " received this = " << this << " who = " << who << std::endl;*/ } andrewm@0: andrewm@0: // These methods register and unregister sources of triggers. andrewm@0: andrewm@0: void registerForTrigger(TriggerSource* src) { andrewm@0: //std::cout<<"registerForTrigger: this = " << this << " src = " << src << std::endl; andrewm@0: andrewm@0: if(src == 0 || (void*)src == (void*)this) andrewm@0: return; andrewm@0: ScopedLock sl(triggerDestMutex_); andrewm@0: src->addTriggerDestination(this); andrewm@0: registeredTriggerSources_.insert(src); andrewm@0: } andrewm@0: andrewm@0: void unregisterForTrigger(TriggerSource* src) { andrewm@0: if(src == 0 || (void*)src == (void*)this) andrewm@0: return; andrewm@0: ScopedLock sl(triggerDestMutex_); andrewm@0: src->removeTriggerDestination(this); andrewm@0: registeredTriggerSources_.erase(src); andrewm@0: } andrewm@0: andrewm@0: void clearTriggers() { andrewm@0: ScopedLock sl(triggerDestMutex_); andrewm@0: std::set::iterator it; andrewm@0: for(it = registeredTriggerSources_.begin(); it != registeredTriggerSources_.end(); it++) andrewm@0: (*it)->removeTriggerDestination(this); andrewm@0: registeredTriggerSources_.clear(); andrewm@0: } andrewm@0: andrewm@0: protected: andrewm@0: // This method is called by a TriggerBase object when it is deleted, so that we know not andrewm@0: // to contact it later when this object is deleted. This is different than unregisterForTrigger() andrewm@0: // because it only removes the reference and does not call the TriggerBase object (which would create andrewm@0: // an infinite loop). andrewm@0: andrewm@0: void triggerSourceDeleted(TriggerSource* src) { registeredTriggerSources_.erase(src); } andrewm@0: andrewm@0: public: andrewm@0: // ***** Destructor ***** andrewm@0: // andrewm@0: // Remove all trigger sources before this object goes away andrewm@0: andrewm@0: virtual ~TriggerDestination() { clearTriggers(); } andrewm@0: andrewm@0: private: andrewm@0: // Keep an internal registry of who we've asked to send us triggers. It's important to keep andrewm@0: // a list of these so that when this object is destroyed, all triggers are automatically unregistered. andrewm@0: std::set registeredTriggerSources_; andrewm@0: CriticalSection triggerDestMutex_; andrewm@0: }; andrewm@0: andrewm@0: andrewm@0: andrewm@0: #endif /* KEYCONTROL_TRIGGER_H */