diff --git a/src/window/sdl2/sdl2_display_window.cpp b/src/window/sdl2/sdl2_display_window.cpp index 6b7eae4..ce43839 100644 --- a/src/window/sdl2/sdl2_display_window.cpp +++ b/src/window/sdl2/sdl2_display_window.cpp @@ -365,16 +365,55 @@ void SDL2DisplayWindow::ExitLoop() ExitRunLoop = true; } +std::unordered_map> SDL2DisplayWindow::Timers; +std::unordered_map SDL2DisplayWindow::TimerHandles; +unsigned long SDL2DisplayWindow::TimerIDs = 0; +Uint32 TimerEventID = SDL_RegisterEvents(1); + +Uint32 SDL2DisplayWindow::ExecTimer(Uint32 interval, void* execID) +{ + // cancel event and stop loop if function not found + if (Timers.find(execID) == Timers.end()) + return 0; + + SDL_Event timerEvent; + SDL_zero(timerEvent); + + timerEvent.user.type = TimerEventID; + timerEvent.user.data1 = execID; + + SDL_PushEvent(&timerEvent); + + return interval; +} + void* SDL2DisplayWindow::StartTimer(int timeoutMilliseconds, std::function onTimer) { - // To do: implement timers + CheckInitSDL(); + + void* execID = (void*)(uintptr_t)++TimerIDs; + void* id = (void*)(uintptr_t)SDL_AddTimer(timeoutMilliseconds, SDL2DisplayWindow::ExecTimer, execID); + + if (!id) return id; + + Timers.insert({execID, onTimer}); + TimerHandles.insert({id, execID}); - return nullptr; + return id; } void SDL2DisplayWindow::StopTimer(void* timerID) { - // To do: implement timers + CheckInitSDL(); + + SDL_RemoveTimer((SDL_TimerID)(uintptr_t)timerID); + + auto execID = TimerHandles.find(timerID); + if (execID == TimerHandles.end()) + return; + + Timers.erase(execID->second); + TimerHandles.erase(timerID); } SDL2DisplayWindow* SDL2DisplayWindow::FindEventWindow(const SDL_Event& event) @@ -401,6 +440,10 @@ SDL2DisplayWindow* SDL2DisplayWindow::FindEventWindow(const SDL_Event& event) void SDL2DisplayWindow::DispatchEvent(const SDL_Event& event) { + // timers are created in a non-window context + if (event.type == TimerEventID) + return OnTimerEvent(event.user); + SDL2DisplayWindow* window = FindEventWindow(event); if (!window) return; @@ -509,6 +552,17 @@ void SDL2DisplayWindow::OnPaintEvent() WindowHost->OnWindowPaint(); } +void SDL2DisplayWindow::OnTimerEvent(const SDL_UserEvent& event) +{ + auto func = Timers.find(event.data1); + + // incase timer was cancelled before we get here + if (func == Timers.end()) + return; + + func->second(); +} + InputKey SDL2DisplayWindow::ScancodeToInputKey(SDL_Scancode keycode) { switch (keycode) diff --git a/src/window/sdl2/sdl2_display_window.h b/src/window/sdl2/sdl2_display_window.h index b8c7e6a..5a51087 100644 --- a/src/window/sdl2/sdl2_display_window.h +++ b/src/window/sdl2/sdl2_display_window.h @@ -67,6 +67,7 @@ class SDL2DisplayWindow : public DisplayWindow void OnMouseWheel(const SDL_MouseWheelEvent& event); void OnMouseMotion(const SDL_MouseMotionEvent& event); void OnPaintEvent(); + static void OnTimerEvent(const SDL_UserEvent& event); InputKey GetMouseButtonKey(const SDL_MouseButtonEvent& event); @@ -86,6 +87,7 @@ class SDL2DisplayWindow : public DisplayWindow static void* StartTimer(int timeoutMilliseconds, std::function onTimer); static void StopTimer(void* timerID); + static Uint32 ExecTimer(Uint32 interval, void* id); DisplayWindowHost* WindowHost = nullptr; SDL2NativeHandle Handle; @@ -102,4 +104,9 @@ class SDL2DisplayWindow : public DisplayWindow static bool ExitRunLoop; static Uint32 PaintEventNumber; static std::unordered_map WindowList; + + static std::unordered_map TimerHandles; + static std::unordered_map> Timers; + static unsigned long TimerIDs; + static Uint32 TimerEventNumber; };