openMSX
StateChangeDistributor.cc
Go to the documentation of this file.
2 #include "StateChangeListener.hh"
3 #include "StateChange.hh"
4 #include "stl.hh"
5 #include <cassert>
6 
7 namespace openmsx {
8 
10 {
11  assert(listeners.empty());
12 }
13 
14 bool StateChangeDistributor::isRegistered(StateChangeListener* listener) const
15 {
16  return contains(listeners, listener);
17 }
18 
20 {
21  assert(!isRegistered(&listener));
22  listeners.push_back(&listener);
23 }
24 
26 {
27  move_pop_back(listeners, rfind_unguarded(listeners, &listener));
28 }
29 
31 {
32  assert(!recorder);
33  recorder = &recorder_;
34 }
35 
37 {
38  (void)recorder_;
39  assert(recorder == &recorder_);
40  recorder = nullptr;
41 }
42 
44 {
45  if (viewOnlyMode && isReplaying()) return;
46 
47  if (isReplaying()) {
48  stopReplay(event->getTime());
49  }
50  distribute(event);
51 }
52 
54 {
55  assert(isReplaying());
56  distribute(event);
57 }
58 
59 void StateChangeDistributor::distribute(const EventPtr& event)
60 {
61  // Iterate over a copy because signalStateChange() may indirect call
62  // back into registerListener().
63  // e.g. signalStateChange() -> .. -> PlugCmd::execute() -> .. ->
64  // Connector::plug() -> .. -> Joystick::plugHelper() ->
65  // registerListener()
66  if (recorder) recorder->signalStateChange(event);
67  auto copy = listeners;
68  for (auto& l : copy) {
69  if (isRegistered(l)) {
70  // it's possible the listener unregistered itself
71  // (but is still present in the copy)
72  l->signalStateChange(event);
73  }
74  }
75 }
76 
77 void StateChangeDistributor::stopReplay(EmuTime::param time)
78 {
79  if (!isReplaying()) return;
80 
81  if (recorder) recorder->stopReplay(time);
82  for (auto& l : listeners) {
83  l->stopReplay(time);
84  }
85 }
86 
88 {
89  if (recorder) {
90  return recorder->isReplaying();
91  }
92  return false;
93 }
94 
95 } // namespace openmsx
auto copy(InputRange &&range, OutputIter out)
Definition: ranges.hh:149
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:92
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:177
void stopReplay(EmuTime::param time)
Explicitly stop replay.
std::shared_ptr< StateChange > EventPtr
void unregisterRecorder(StateChangeRecorder &recorder)
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.
auto rfind_unguarded(RANGE &range, const VAL &val)
Similar to the find(_if)_unguarded functions above, but searches from the back to front...
Definition: stl.hh:152