Scheduler
The scheduler provides high-level functionalities to emit events. Using the scheduler should be preferred over using a dispatcher directly. Moreover, it provides the organization of globally available event loops.
-
template<Dispatchable Dispatcher>
class Scheduler : public obscura::Singleton<SchedulerImpl<Dispatcher>> Scheduler is a singleton that manages all the loops in the application. The class inherits from obscura::SchedulerImpl that implements all the main functionalities. In order to use the scheduler, retrieve an instance of the scheduler using obscura::Scheduler::getInstance().
- Template Parameters:
Dispatcher – Type of the dispatcher to be used by the scheduler.
-
template<Dispatchable Dispatcher>
class SchedulerImpl Public Functions
-
inline auto getMainLoop() -> MainLoop<Dispatcher>*
-
inline auto getSyncLoop(const std::string &name) -> SyncLoop<Dispatcher, MainLoop<Dispatcher>>*
-
inline auto getAsyncLoop(const std::string &name) -> AsyncLoop<Dispatcher>*
-
inline void startMainLoop()
-
inline void stopMainLoop()
-
inline auto createSyncLoop(const std::string &name, const LoopConfig &config) -> SyncLoop<Dispatcher, MainLoop<Dispatcher>>*
Creates a new synchronous loop and registers it with the scheduler.
- Parameters:
name – Name of the loop. The name is required to schedule event_system on the loop.
config – Config for the loop.
- Returns:
Returns a pointer to the newly created loop.
-
inline auto createAsyncLoop(const std::string &name, const FPS &fps) -> AsyncLoop<Dispatcher>*
Creates a new asynchronous loop and registers it with the scheduler.
- Parameters:
name – Name of the loop. The name is required to schedule event_system on the loop.
fps – FPS of the loop.
- Returns:
Returns a pointer to the newly created loop.
-
template<class Event>
inline void scheduleOnce(Event &&event, const std::string &loopName) Schedules an event on the specified loop.
- Template Parameters:
Event – Type of the event.
- Parameters:
event – Event to be scheduled.
loopName – Name of the loop on which the event is to be scheduled.
-
template<class Event>
inline void scheduleOnce(Event &&event) Schedules an event on the main loop.
- Template Parameters:
Event – Type of the event.
- Parameters:
event – Event to be scheduled.
-
template<class Event, class Duration>
inline void scheduleOnce(Event &&event, const Duration &delay, const std::string &loopName) Schedules an event on the specified loop after a delay.
- Template Parameters:
Event – Type of the event.
Duration – Type of the duration. Usually, a std::chrono::duration.
- Parameters:
event – Event to be scheduled.
delay – Delay after which the event is to be scheduled.
loopName – Name of the loop on which the event is to be scheduled.
-
template<class Event, class Duration>
inline void scheduleOnce(Event &&event, const Duration &delay) Schedules an event on the main loop.
- Template Parameters:
Event – Type of the event.
Duration – Type of the duration. Usually, a std::chrono::duration.
- Parameters:
event – Event to be scheduled.
delay – Delay after which the event is to be scheduled.
-
template<class Listener>
inline void registerListener(Listener &listener, const std::string &loopName)
-
template<class Listener>
inline void registerListener(Listener &listener) Registers a listener with the main loop.
- Template Parameters:
Listener – Type of the listener.
- Parameters:
listener – The listener to be registered.
-
template<class Listener>
inline void unregisterListener(Listener &listener, const std::string &loopName) Unregisters a listener from the specified loop.
- Template Parameters:
Listener – Type of the listener.
- Parameters:
listener – The listener to be unregistered.
loopName – Name of the loop from which the listener is to be unregistered.
-
template<class Listener>
inline void unregisterListener(Listener &listener) Unregisters a listener from the main loop.
- Template Parameters:
Listener – Type of the listener.
- Parameters:
listener – The listener to be unregistered.
-
inline auto getMainLoop() -> MainLoop<Dispatcher>*
Examples
Schedule events with a delay
#include <obscura/obscura.hxx>
using namespace obscura;
using namespace std::chrono_literals;
class Listener {
public:
void onKeyPressed(const KeyPressedEvent& event) { // NOLINT(readability-convert-member-functions-to-static)
// The function cannot be static because it needs to be registered as a callback.
logInfo("Key pressed: {}", event.getKey());
}
};
auto main() -> int {
try {
auto application = obscura::Application<HeadlessWindow>();
auto listener = Listener {};
auto defaultApplicationListener = DefaultApplicationListener<Application<HeadlessWindow>>(application);
auto& scheduler = Scheduler<Dispatcher>::getInstance();
scheduler.registerListener(listener);
scheduler.registerListener(defaultApplicationListener);
for (std::size_t i = 0; i < 10;
++i) { // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
auto event = KeyPressedEvent { static_cast<int>(i) };
logInfo("Scheduling event with key {} and a {}s delay", event.getKey(), i);
scheduler.scheduleOnce(event, std::chrono::seconds { i });
}
scheduler.scheduleOnce(
WindowEvent(EventCause::WindowClosed),
10s); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
application.run();
} catch (const std::exception& e) {
logError("Exception caught: {}", e.what());
}
return EXIT_SUCCESS;
}
Use multiple loops
#include <obscura/obscura.hxx>
using namespace obscura;
using namespace std::chrono_literals;
class Listener {
public:
explicit Listener(std::string shoutOut)
: shoutOut(std::move(shoutOut)) {
}
void onTick(const TickEvent& /*unused*/) {
logInfo("{}", shoutOut);
}
private:
std::string shoutOut;
};
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
auto main() -> int {
try {
auto application = obscura::Application<HeadlessWindow>();
auto defaultApplicationListener = DefaultApplicationListener<Application<HeadlessWindow>>(application);
auto mainListener = Listener("cha");
auto syncListener1 = Listener("Dooo!");
auto syncListener2 = Listener("MAA!");
auto& scheduler = Scheduler<Dispatcher>::getInstance();
scheduler.registerListener(mainListener);
scheduler.registerListener(defaultApplicationListener);
auto loopConfig1 = LoopConfig::runAtFractionOfBaseLoop(0.5).build();
scheduler.createSyncLoop("syncLoop1", loopConfig1);
auto loopConfig2 = LoopConfig::runAtFractionOfBaseLoop(0.25).build();
scheduler.createSyncLoop("syncLoop2", loopConfig2);
scheduler.registerListener(syncListener1, "syncLoop1");
scheduler.registerListener(syncListener2, "syncLoop2");
scheduler.scheduleOnce(WindowEvent { EventCause::WindowClosed }, 2s);
application.run();
} catch (const std::exception& e) {
logError("Exception caught: {}", e.what());
}
return EXIT_SUCCESS;
}
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
Listen to inputs in a headless window
#include <chrono>
#include <obscura/obscura.hxx>
#include <thread>
using namespace obscura;
class InputListener {
public:
// NOLINTBEGIN(readability-convert-member-functions-to-static)
[[maybe_unused]] void onKeyPressed(const KeyPressedEvent& event) {
logInfo("Key pressed: {}", event.getKey());
}
[[maybe_unused]] void onKeyReleased(const KeyReleasedEvent& event) {
logInfo("Key released: {}", event.getKey());
}
[[maybe_unused]] void onMouseMoved(const MouseMovedEvent& event) {
logInfo("Mouse moved to x: {}, y: {}", event.getCurrentPosition().x, event.getCurrentPosition().y);
}
// NOLINTEND(readability-convert-member-functions-to-static)
};
// NOLINTBEGIN(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
auto main() -> int {
try {
auto application = obscura::Application<HeadlessWindow>();
auto inputListener = InputListener {};
auto applicationListener = DefaultApplicationListener<Application<HeadlessWindow>>(application);
Scheduler<Dispatcher>::getInstance().registerListener(inputListener);
Scheduler<Dispatcher>::getInstance().registerListener(applicationListener);
std::thread thread1([&application]() {
std::this_thread::sleep_for(std::chrono::seconds { 2 });
application.getWindowEventEmitter().pressKey(100);
});
std::thread thread2([&application]() {
std::this_thread::sleep_for(std::chrono::seconds { 2 });
application.getWindowEventEmitter().pressKey(90);
std::this_thread::sleep_for(std::chrono::seconds { 3 });
Scheduler<Dispatcher>::getInstance().scheduleOnce(WindowEvent(EventCause::WindowClosed));
});
std::thread thread3([&application]() {
std::this_thread::sleep_for(std::chrono::seconds { 1 });
application.getWindowEventEmitter().moveMouseFromTo(glm::vec2 { 0, 0 }, glm::vec2 { 200, 200 }, 200, 0.2F);
});
application.run();
thread1.join();
thread2.join();
thread3.join();
} catch (const std::exception& e) {
logError("Exception caught: {}", e.what());
}
return EXIT_SUCCESS;
}
// NOLINTEND(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)