#include "cru/platform/gui/sdl/UiApplication.h" #include "cru/base/Base.h" #include "cru/platform/graphics/Factory.h" #include "cru/platform/gui/sdl/Base.h" #include "cru/platform/gui/sdl/Clipboard.h" #include "cru/platform/gui/sdl/Cursor.h" #include "cru/platform/gui/sdl/Window.h" #include #include #include #include #include #include #include #include namespace cru::platform::gui::sdl { SdlUiApplication::SdlUiApplication(graphics::IGraphicsFactory* graphics_factory, bool release_graphics_factory) : graphics_factory_(graphics_factory), release_graphics_factory_(release_graphics_factory), quit_code_(0) { CheckSdlReturn(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)); empty_event_type_ = SDL_RegisterEvents(1); CheckSdlReturn(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)); CheckSdlReturn(SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3)); CheckSdlReturn(SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2)); CheckSdlReturn(SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)); cursor_manager_ = std::make_unique(); clipboard_ = std::make_unique(); } SdlUiApplication::~SdlUiApplication() { SDL_Quit(); delete_later_pool_.Clean(); if (release_graphics_factory_) { delete graphics_factory_; } } int SdlUiApplication::Run() { while (true) { auto timeout = timers_.NextTimeout(std::chrono::steady_clock::now()); SDL_Event event; bool has_event = false; if (timeout) { if (*timeout == std::chrono::milliseconds::zero()) { has_event = SDL_PollEvent(&event); } else { has_event = SDL_WaitEventTimeout(&event, timeout->count()); } } else { CheckSdlReturn(SDL_WaitEvent(&event)); has_event = true; } if (has_event) { if (event.type == SDL_EVENT_QUIT) { break; } // char buf[512]; // SDL_GetEventDescription(&event, buf, sizeof(buf) / sizeof(*buf)); // CruLogDebug(kLogTag, "{}", buf); DispatchEvent(event); } else { if (auto result = timers_.Update(std::chrono::steady_clock::now())) { result->data(); } } delete_later_pool_.Clean(); } for (const auto& handler : this->quit_handlers_) { handler(); } return quit_code_; } void SdlUiApplication::RequestQuit(int quit_code) { quit_code_ = quit_code; SDL_Event event; event.type = SDL_EVENT_QUIT; event.quit.timestamp = SDL_GetTicksNS(); CheckSdlReturn(SDL_PushEvent(&event)); } void SdlUiApplication::AddOnQuitHandler(std::function handler) { this->quit_handlers_.push_back(std::move(handler)); } bool SdlUiApplication::IsQuitOnAllWindowClosed() { return is_quit_on_all_window_closed_; } void SdlUiApplication::SetQuitOnAllWindowClosed( bool quit_on_all_window_closed) { is_quit_on_all_window_closed_ = quit_on_all_window_closed; } long long SdlUiApplication::SetImmediate(std::function action) { return SetTimeout(std::chrono::milliseconds::zero(), std::move(action)); } long long SdlUiApplication::SetTimeout(std::chrono::milliseconds milliseconds, std::function action) { return SetTimer(milliseconds, std::move(action), false); } long long SdlUiApplication::SetInterval(std::chrono::milliseconds milliseconds, std::function action) { return SetTimer(milliseconds, std::move(action), true); } void SdlUiApplication::CancelTimer(long long id) { return timers_.Remove(static_cast(id)); } void SdlUiApplication::DeleteLater(Object* object) { delete_later_pool_.Add(object); } std::vector SdlUiApplication::GetAllWindow() { std::vector windows(windows_.size()); std::ranges::copy(windows_, windows.begin()); return windows; } INativeWindow* SdlUiApplication::CreateWindow() { return new SdlWindow(this); } cru::platform::graphics::IGraphicsFactory* SdlUiApplication::GetGraphicsFactory() { return graphics_factory_; } ICursorManager* SdlUiApplication::GetCursorManager() { return cursor_manager_.get(); } IClipboard* SdlUiApplication::GetClipboard() { return clipboard_.get(); } IMenu* SdlUiApplication::GetApplicationMenu() { return nullptr; } void SdlUiApplication::RegisterWindow(SdlWindow* window) { windows_.push_back(window); } void SdlUiApplication::UnregisterWindow(SdlWindow* window) { std::erase(windows_, window); } void SdlUiApplication::RunOnMainThread(std::function action) { auto p = new std::function(std::move(action)); SDL_RunOnMainThread( [](void* userdata) { auto action = static_cast*>(userdata); (*action)(); delete action; }, p, false); } void SdlUiApplication::PostEmptyEvent() { SDL_Event event; SDL_zero(event); event.type = empty_event_type_; event.user.timestamp = SDL_GetTicksNS(); SDL_PushEvent(&event); } long long SdlUiApplication::SetTimer(std::chrono::milliseconds milliseconds, std::function action, bool repeat) { PostEmptyEvent(); return timers_.Add(std::move(action), milliseconds, repeat); } bool SdlUiApplication::DispatchEvent(const SDL_Event& event) { for (auto window : windows_) { if (window->HandleEvent(&event)) { return true; } } return false; } } // namespace cru::platform::gui::sdl