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.cpp: 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: #include "Trigger.h" andrewm@0: andrewm@0: #undef DEBUG_TRIGGERS andrewm@0: andrewm@0: void TriggerSource::sendTrigger(timestamp_type timestamp) { andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << "sendTrigger (" << this << ")\n"; andrewm@0: #endif andrewm@0: andrewm@0: if(triggerDestinationsModified_) { andrewm@0: ScopedLock sl(triggerSourceMutex_); andrewm@0: processAddRemoveQueue(); andrewm@0: } andrewm@0: andrewm@0: std::set::iterator it = triggerDestinations_.begin(); andrewm@0: TriggerDestination* target; andrewm@0: while(it != triggerDestinations_.end()) { // Advance the iterator before sending the trigger andrewm@0: target = *it; // in case the triggerReceived routine causes the object to unregister andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << " --> " << target << std::endl; andrewm@0: #endif andrewm@0: target->triggerReceived(this, timestamp); andrewm@0: it++; andrewm@0: } andrewm@0: } andrewm@0: andrewm@0: void TriggerSource::addTriggerDestination(TriggerDestination* dest) { andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << "addTriggerDestination (" << this << "): " << dest << "\n"; andrewm@0: #endif andrewm@0: if(dest == 0 || (void*)dest == (void*)this) andrewm@0: return; andrewm@0: ScopedLock sl(triggerSourceMutex_); andrewm@0: // Make sure this trigger isn't already present andrewm@0: if(triggerDestinations_.count(dest) == 0) { andrewm@0: triggersToAdd_.insert(dest); andrewm@0: triggerDestinationsModified_ = true; andrewm@0: } andrewm@0: // If the trigger is also slated to be removed, cancel that request andrewm@0: if(triggersToRemove_.count(dest) != 0) andrewm@0: triggersToRemove_.erase(dest); andrewm@0: } andrewm@0: andrewm@0: void TriggerSource::removeTriggerDestination(TriggerDestination* dest) { andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << "removeTriggerDestination (" << this << "): " << dest << "\n"; andrewm@0: #endif andrewm@0: ScopedLock sl(triggerSourceMutex_); andrewm@0: // Check whether this trigger is actually present andrewm@0: if(triggerDestinations_.count(dest) != 0) { andrewm@0: triggersToRemove_.insert(dest); andrewm@0: triggerDestinationsModified_ = true; andrewm@0: } andrewm@0: // If the trigger is also slated to be added, cancel that request andrewm@0: if(triggersToAdd_.count(dest) != 0) andrewm@0: triggersToAdd_.erase(dest); andrewm@0: } andrewm@0: andrewm@0: void TriggerSource::clearTriggerDestinations() { andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << "clearTriggerDestinations (" << this << ")\n"; andrewm@0: #endif andrewm@0: ScopedLock sl(triggerSourceMutex_); andrewm@0: processAddRemoveQueue(); andrewm@0: std::set::iterator it; andrewm@0: for(it = triggerDestinations_.begin(); it != triggerDestinations_.end(); ++it) andrewm@0: (*it)->triggerSourceDeleted(this); andrewm@0: triggerDestinations_.clear(); andrewm@0: } andrewm@0: andrewm@0: // Process everything in the add and remove groups and transfer them andrewm@0: // into the main set of trigger destinations. Do this with mutex locked. andrewm@0: void TriggerSource::processAddRemoveQueue() { andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << "processAddRemoveQueue (" << this << ")\n"; andrewm@0: #endif andrewm@0: std::set::iterator it; andrewm@0: for(it = triggersToAdd_.begin(); it != triggersToAdd_.end(); ++it) { andrewm@0: triggerDestinations_.insert(*it); andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << " --> added " << *it << std::endl; andrewm@0: #endif andrewm@0: } andrewm@0: for(it = triggersToRemove_.begin(); it != triggersToRemove_.end(); ++it) { andrewm@0: triggerDestinations_.erase(*it); andrewm@0: #ifdef DEBUG_TRIGGERS andrewm@0: std::cerr << " --> removed " << *it << std::endl; andrewm@0: #endif andrewm@0: } andrewm@0: triggersToAdd_.clear(); andrewm@0: triggersToRemove_.clear(); andrewm@0: triggerDestinationsModified_ = false; andrewm@0: }