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: }