OXYGENHUB
◆ main openmsx / src / events / EventDistributor.hh
2.6 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef EVENTDISTRIBUTOR_HH
2
#define EVENTDISTRIBUTOR_HH
3
4
#include "Event.hh"
5
6
#include <array>
7
#include <cstdint>
8
#include <mutex>
9
#include <optional>
10
#include <utility>
11
#include <vector>
12
13
namespace openmsx {
14
15
class Reactor;
16
class EventListener;
17
18
class EventDistributor
19
{
20
public:
21
	/** Priorities from high to low, higher priority listeners can block
22
	  * events for lower priority listeners.
23
	  */
24
	enum class Priority : uint8_t {
25
		OTHER,
26
		HOTKEY_HIGH, // above IMGUI
27
		IMGUI,
28
		HOTKEY_LOW, // below IMGUI
29
		MSX,
30
		LOWEST, // should only be used internally in EventDistributor
31
	};
32
	friend auto operator<=>(Priority x, Priority y) { return std::to_underlying(x) <=> std::to_underlying(y); }
33
34
	explicit EventDistributor(Reactor& reactor);
35
36
	/**
37
	 * Registers a given object to receive certain events.
38
	 * @param type The type of the events you want to receive.
39
	 * @param listener Listener that will be notified when an event arrives.
40
	 * @param priority Listeners have a priority, higher priority listeners
41
	 *                 can block events for lower priority listeners.
42
	 */
43
	void registerEventListener(EventType type, EventListener& listener,
44
	                           Priority priority = Priority::OTHER);
45
46
	/**
47
	 * Unregisters a previously registered event listener.
48
	 * @param type The type of the events the listener should no longer receive.
49
	 * @param listener Listener to unregister.
50
	 */
51
	void unregisterEventListener(EventType type, EventListener& listener);
52
53
	/** Schedule the given event for delivery. Actual delivery happens
54
	  * when the deliverEvents() method is called. Events are always
55
	  * in the main thread.
56
	  */
57
	void distributeEvent(Event&& event);
58
59
	/** This actually delivers the events. It may only be called from the
60
	  * main loop in Reactor (and only from the main thread). Also see
61
	  * the distributeEvent() method.
62
	  * @param timeoutMs If provided, wait up to this many milliseconds for
63
	  *        SDL events before processing. Used when emulation is blocked
64
	  *        to avoid busy-waiting while remaining responsive to input.
65
	  */
66
	void deliverEvents(std::optional<int> timeoutMs = std::nullopt);
67
68
	[[nodiscard]] Reactor& getReactor() { return reactor; }
69
70
private:
71
	[[nodiscard]] bool isRegistered(EventType type, EventListener* listener) const;
72
73
private:
74
	Reactor& reactor;
75
76
	struct Entry {
77
		Priority priority;
78
		EventListener* listener;
79
	};
80
	using PriorityMap = std::vector<Entry>; // sorted on priority
81
	std::array<PriorityMap, size_t(EventType::NUM_EVENT_TYPES)> listeners;
82
	using EventQueue = std::vector<Event>;
83
	EventQueue scheduledEvents;
84
	std::mutex mutex; // lock data structures
85
};
86
87
} // namespace openmsx
88
89
#endif