openMSX
StateChangeDistributor.cc
Go to the documentation of this file.
2 #include "StateChangeListener.hh"
3 #include "StateChange.hh"
4 #include "stl.hh"
5 #include <algorithm>
6 #include <cassert>
7 
8 namespace openmsx {
9 
11  : recorder(nullptr)
12  , viewOnlyMode(false)
13 {
14 }
15 
17 {
18  assert(listeners.empty());
19 }
20 
21 bool StateChangeDistributor::isRegistered(StateChangeListener* listener) const
22 {
23  return contains(listeners, listener);
24 }
25 
27 {
28  assert(!isRegistered(&listener));
29  listeners.push_back(&listener);
30 }
31 
33 {
34  move_pop_back(listeners, rfind_unguarded(listeners, &listener));
35 }
36 
38 {
39  assert(!recorder);
40  recorder = &recorder_;
41 }
42 
44 {
45  (void)recorder_;
46  assert(recorder == &recorder_);
47  recorder = nullptr;
48 }
49 
51 {
52  if (viewOnlyMode && isReplaying()) return;
53 
54  if (isReplaying()) {
55  stopReplay(event->getTime());
56  }
57  distribute(event);
58 }
59 
61 {
62  assert(isReplaying());
63  distribute(event);
64 }
65 
66 void StateChangeDistributor::distribute(const EventPtr& event)
67 {
68  // Iterate over a copy because signalStateChange() may indirect call
69  // back into registerListener().
70  // e.g. signalStateChange() -> .. -> PlugCmd::execute() -> .. ->
71  // Connector::plug() -> .. -> Joystick::plugHelper() ->
72  // registerListener()
73  if (recorder) recorder->signalStateChange(event);
74  auto copy = listeners;
75  for (auto& l : copy) {
76  if (isRegistered(l)) {
77  // it's possible the listener unregistered itself
78  // (but is still present in the copy)
79  l->signalStateChange(event);
80  }
81  }
82 }
83 
84 void StateChangeDistributor::stopReplay(EmuTime::param time)
85 {
86  if (!isReplaying()) return;
87 
88  if (recorder) recorder->stopReplay(time);
89  for (auto& l : listeners) {
90  l->stopReplay(time);
91  }
92 }
93 
95 {
96  if (recorder) {
97  return recorder->isReplaying();
98  }
99  return false;
100 }
101 
102 } // namespace openmsx
void unregisterListener(StateChangeListener &listener)
bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:102
void distributeNew(const EventPtr &event)
Deliver the event to all registered listeners MSX input devices should call the distributeNew() versi...
void registerListener(StateChangeListener &listener)
(Un)registers the given object to receive state change events.
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition: stl.hh:192
void stopReplay(EmuTime::param time)
Explicitly stop replay.
std::shared_ptr< StateChange > EventPtr
void unregisterRecorder(StateChangeRecorder &recorder)
auto rfind_unguarded(RANGE &range, const VAL &val) -> decltype(std::begin(range))
Similar to the find(_if)_unguarded functions above, but searches from the back to front...
Definition: stl.hh:164
void registerRecorder(StateChangeRecorder &recorder)
(Un)registers the given object to receive state change events.
virtual bool isReplaying() const =0
void distributeReplay(const EventPtr &event)
virtual void signalStateChange(const std::shared_ptr< StateChange > &event)=0
This method gets called when a StateChange event occurs.
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
virtual void stopReplay(EmuTime::param time)=0
This method gets called when we switch from replayed events to live events.