diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.cpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.cpp index b9b4a04e6..87440f801 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.cpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.cpp @@ -7,6 +7,7 @@ // #include "MultiMediaTarget.hpp" +#include using namespace Analyser::Dynamic; @@ -27,3 +28,29 @@ bool MultiMediaTarget::insert_media(const Analyser::Static::Media &media) { } return inserted; } + +MultiMediaChangeObserver::MultiMediaChangeObserver(const std::vector> &machines) { + for(const auto &machine: machines) { + auto media_change_observer = machine->media_change_observer(); + if(media_change_observer) targets_.push_back(media_change_observer); + } +} + +using ChangeEffect = MachineTypes::MediaChangeObserver::ChangeEffect; + +ChangeEffect MultiMediaChangeObserver::effect_for_file_did_change(const std::string &name) const { + if(targets_.empty()) { + return ChangeEffect::None; + } + + std::unordered_set effects; + for(const auto &target: targets_) { + effects.insert(target->effect_for_file_did_change(name)); + } + + // No agreement => restart. + if(effects.size() > 1) { + return ChangeEffect::RestartMachine; + } + return *effects.begin(); +} diff --git a/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.hpp b/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.hpp index b1786441f..5e2692e5f 100644 --- a/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.hpp +++ b/Analyser/Dynamic/MultiMachine/Implementation/MultiMediaTarget.hpp @@ -33,4 +33,15 @@ private: std::vector targets_; }; +struct MultiMediaChangeObserver: public MachineTypes::MediaChangeObserver { +public: + MultiMediaChangeObserver(const std::vector> &); + + // Below is the standard MediaTarget::Machine interface; see there for documentation. + ChangeEffect effect_for_file_did_change(const std::string &) const final; + +private: + std::vector targets_; +}; + } diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp index e45ee8d38..562df1b0c 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.cpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.cpp @@ -27,7 +27,8 @@ MultiMachine::MultiMachine(std::vector> &&machin audio_producer_(machines_, machines_mutex_), joystick_machine_(machines_), keyboard_machine_(machines_), - media_target_(machines_) + media_target_(machines_), + media_change_observer_(machines_) { timed_machine_.set_delegate(this); } @@ -52,6 +53,7 @@ Provider(MachineTypes::AudioProducer, audio_producer, audio_producer_) Provider(MachineTypes::JoystickMachine, joystick_machine, joystick_machine_) Provider(MachineTypes::KeyboardMachine, keyboard_machine, keyboard_machine_) Provider(MachineTypes::MediaTarget, media_target, media_target_) +Provider(MachineTypes::MediaChangeObserver, media_change_observer, media_change_observer_) MachineTypes::MouseMachine *MultiMachine::mouse_machine() { // TODO. diff --git a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp index 0dcdd965a..ac2679fff 100644 --- a/Analyser/Dynamic/MultiMachine/MultiMachine.hpp +++ b/Analyser/Dynamic/MultiMachine/MultiMachine.hpp @@ -58,6 +58,7 @@ public: MachineTypes::KeyboardMachine *keyboard_machine() final; MachineTypes::MouseMachine *mouse_machine() final; MachineTypes::MediaTarget *media_target() final; + MachineTypes::MediaChangeObserver *media_change_observer() final; void *raw_pointer() final; private: @@ -73,6 +74,7 @@ private: MultiJoystickMachine joystick_machine_; MultiKeyboardMachine keyboard_machine_; MultiMediaTarget media_target_; + MultiMediaChangeObserver media_change_observer_; void pick_first(); bool has_picked_ = false; diff --git a/Machines/DynamicMachine.hpp b/Machines/DynamicMachine.hpp index 0a8abd46e..dd75eb439 100644 --- a/Machines/DynamicMachine.hpp +++ b/Machines/DynamicMachine.hpp @@ -31,6 +31,7 @@ struct DynamicMachine { virtual MachineTypes::KeyboardMachine *keyboard_machine() = 0; virtual MachineTypes::MouseMachine *mouse_machine() = 0; virtual MachineTypes::MediaTarget *media_target() = 0; + virtual MachineTypes::MediaChangeObserver *media_change_observer() = 0; /*! Provides a raw pointer to the underlying machine if and only if this dynamic machine really is @@ -65,6 +66,7 @@ SpecialisedGet(MachineTypes::JoystickMachine, joystick_machine) SpecialisedGet(MachineTypes::KeyboardMachine, keyboard_machine) SpecialisedGet(MachineTypes::MouseMachine, mouse_machine) SpecialisedGet(MachineTypes::MediaTarget, media_target) +SpecialisedGet(MachineTypes::MediaChangeObserver, media_change_observer) #undef SpecialisedGet diff --git a/Machines/MediaTarget.hpp b/Machines/MediaTarget.hpp index 037193d06..b2ef60b41 100644 --- a/Machines/MediaTarget.hpp +++ b/Machines/MediaTarget.hpp @@ -30,7 +30,9 @@ struct MediaTarget { // inserted, ejected and ignored. That'll allow the owner to know which media is actually // being consumed, so it knows what to monitor (if available on the host system) and hence // if/when to call effect_for_file_did_change. +}; +struct MediaChangeObserver { enum class ChangeEffect { None, ReinsertMedia, @@ -58,7 +60,7 @@ struct MediaTarget { might be appropriate depending on whether it is more likely that execution will continue correctly with a simple media swap or whether this implies that previous state should be completely discarded. */ - virtual ChangeEffect effect_for_file_did_change([[maybe_unused]] const std::string &file_name) { + virtual ChangeEffect effect_for_file_did_change([[maybe_unused]] const std::string &file_name) const { return ChangeEffect::None; } }; diff --git a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp index 95f7d1cb6..05f8c8a4c 100644 --- a/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp +++ b/Machines/Sinclair/ZXSpectrum/ZXSpectrum.cpp @@ -126,6 +126,7 @@ template class ConcreteMachine: public MachineTypes::AudioProducer, public MachineTypes::JoystickMachine, public MachineTypes::MappedKeyboardMachine, + public MachineTypes::MediaChangeObserver, public MachineTypes::MediaTarget, public MachineTypes::ScanProducer, public MachineTypes::TimedMachine, @@ -696,7 +697,7 @@ template class ConcreteMachine: return !media.tapes.empty() || (!media.disks.empty() && model == Model::Plus3); } - ChangeEffect effect_for_file_did_change(const std::string &file_name) override { + ChangeEffect effect_for_file_did_change(const std::string &file_name) const override { const auto disk = fdc_->disk(); return disk && disk->represents(file_name) && disk->has_written() ? ChangeEffect::None : ChangeEffect::RestartMachine; diff --git a/Machines/Utility/TypedDynamicMachine.hpp b/Machines/Utility/TypedDynamicMachine.hpp index 857e90bcf..348eb0dea 100644 --- a/Machines/Utility/TypedDynamicMachine.hpp +++ b/Machines/Utility/TypedDynamicMachine.hpp @@ -40,6 +40,7 @@ public: Provide(MachineTypes::KeyboardMachine, keyboard_machine) Provide(MachineTypes::MouseMachine, mouse_machine) Provide(MachineTypes::MediaTarget, media_target) + Provide(MachineTypes::MediaChangeObserver, media_change_observer) #undef Provide diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index d4cb31279..7a3ea34b7 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -373,12 +373,12 @@ struct ActivityObserver: public Activity::Observer { - (CSMachineChangeEffect)effectForFileAtURLDidChange:(nonnull NSURL *)url { @synchronized(self) { - const auto mediaTarget = _machine->media_target(); - if(!mediaTarget) { + const auto mediaChangeObserver = _machine->media_change_observer(); + if(!mediaChangeObserver) { return CSMachineChangeEffectNone; } - const auto effect = mediaTarget->effect_for_file_did_change([url fileSystemRepresentation]); - using ChangeEffect = MachineTypes::MediaTarget::ChangeEffect; + const auto effect = mediaChangeObserver->effect_for_file_did_change([url fileSystemRepresentation]); + using ChangeEffect = MachineTypes::MediaChangeObserver::ChangeEffect; switch(effect) { case ChangeEffect::None: return CSMachineChangeEffectNone;