#include "cru/osx/gui/UiApplication.hpp" #include "cru/osx/graphics/quartz/Factory.hpp" #include #include #include #include #include @interface AppDelegate : NSObject - (id)init:(cru::platform::gui::osx::details::OsxUiApplicationPrivate*)p; - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender; - (void)applicationWillTerminate:(NSNotification*)notification; @end namespace cru::platform::gui::osx { namespace details { class OsxUiApplicationPrivate { friend OsxUiApplication; public: explicit OsxUiApplicationPrivate(OsxUiApplication* osx_ui_application) : osx_ui_application_(osx_ui_application) { app_delegate_ = [[AppDelegate alloc] init:this]; } CRU_DELETE_COPY(OsxUiApplicationPrivate) CRU_DELETE_MOVE(OsxUiApplicationPrivate) ~OsxUiApplicationPrivate() = default; void CallQuitHandlers(); private: OsxUiApplication* osx_ui_application_; AppDelegate* app_delegate_; std::vector> quit_handlers_; long long current_timer_id_ = 1; std::unordered_map> next_tick_; std::unordered_map timers_; std::unique_ptr quartz_graphics_factory_; }; void OsxUiApplicationPrivate::CallQuitHandlers() { for (const auto& handler : quit_handlers_) { handler(); } } } OsxUiApplication::OsxUiApplication() : OsxGuiResource(this), p_(new details::OsxUiApplicationPrivate(this)) { [NSApp setDelegate:p_->app_delegate_]; p_->quartz_graphics_factory_ = std::make_unique(); } OsxUiApplication::~OsxUiApplication() {} int OsxUiApplication::Run() { [NSApp run]; return 0; } void OsxUiApplication::RequestQuit(int quit_code) { [NSApp terminate:[NSNumber numberWithInteger:quit_code]]; } void OsxUiApplication::AddOnQuitHandler(std::function handler) { p_->quit_handlers_.push_back(std::move(handler)); } long long OsxUiApplication::SetImmediate(std::function action) { const long long id = p_->current_timer_id_++; p_->next_tick_.emplace(id, std::move(action)); [[NSRunLoop mainRunLoop] performBlock:^{ const auto i = p_->next_tick_.find(id); if (i != p_->next_tick_.cend()) { i->second(); } p_->next_tick_.erase(i); }]; return id; } long long OsxUiApplication::SetTimeout(std::chrono::milliseconds milliseconds, std::function action) { long long id = p_->current_timer_id_++; p_->timers_.emplace(id, [NSTimer scheduledTimerWithTimeInterval:milliseconds.count() / 1000.0 repeats:false block:^(NSTimer* timer) { action(); p_->timers_.erase(id); }]); return id; } long long OsxUiApplication::SetInterval(std::chrono::milliseconds milliseconds, std::function action) { long long id = p_->current_timer_id_++; p_->timers_.emplace(id, [NSTimer scheduledTimerWithTimeInterval:milliseconds.count() / 1000.0 repeats:true block:^(NSTimer* timer) { action(); }]); return id; } void OsxUiApplication::CancelTimer(long long id) { p_->next_tick_.erase(id); auto i = p_->timers_.find(id); if (i != p_->timers_.cend()) { [i->second invalidate]; p_->timers_.erase(i); } } } @implementation AppDelegate cru::platform::gui::osx::details::OsxUiApplicationPrivate* _p; - (id)init:(cru::platform::gui::osx::details::OsxUiApplicationPrivate*)p { _p = p; return self; } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender { return NSApplicationTerminateReply::NSTerminateNow; } - (void)applicationWillTerminate:(NSNotification*)notification { _p->CallQuitHandlers(); } @end