/****************************************************************************** * The MIT License (MIT) * * Copyright (c) 2022-2026 Baldur Karlsson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ #include "apple_window.h" #include "official/metal-cpp.h" static NS::Application *pSharedApplication = NULL; MyAppDelegate *AppleWindow::pAppDelegate = NULL; class MyAppDelegate : public NS::ApplicationDelegate { public: ~MyAppDelegate(); NS::Menu *createMenuBar(); virtual void applicationWillFinishLaunching(NS::Notification *pNotification) override; virtual void applicationDidFinishLaunching(NS::Notification *pNotification) override; virtual bool applicationShouldTerminateAfterLastWindowClosed(NS::Application *pSender) override; void CreateWindow(int width, int height, const char *title); NS::View *GetContentView(); NS::Window *GetWindow(); private: NS::Window *_pWindow; }; MyAppDelegate::~MyAppDelegate() { _pWindow->release(); } NS::Menu *MyAppDelegate::createMenuBar() { using NS::StringEncoding::UTF8StringEncoding; NS::Menu *pMainMenu = NS::Menu::alloc()->init(); NS::MenuItem *pAppMenuItem = NS::MenuItem::alloc()->init(); NS::Menu *pAppMenu = NS::Menu::alloc()->init(NS::String::string("Appname", UTF8StringEncoding)); NS::String *appName = NS::RunningApplication::currentApplication()->localizedName(); NS::String *quitItemName = NS::String::string("Quit ", UTF8StringEncoding)->stringByAppendingString(appName); SEL quitCb = NS::MenuItem::registerActionCallback("appQuit", [](void *, SEL, const NS::Object *pSender) { NS::Application *pApp = NS::Application::sharedApplication(); pApp->terminate(pSender); }); NS::MenuItem *pAppQuitItem = pAppMenu->addItem(quitItemName, quitCb, NS::String::string("q", UTF8StringEncoding)); pAppQuitItem->setKeyEquivalentModifierMask(NS::EventModifierFlagCommand); pAppMenuItem->setSubmenu(pAppMenu); NS::MenuItem *pWindowMenuItem = NS::MenuItem::alloc()->init(); NS::Menu *pWindowMenu = NS::Menu::alloc()->init(NS::String::string("Window", UTF8StringEncoding)); SEL closeWindowCb = NS::MenuItem::registerActionCallback("windowClose", [](void *, SEL, const NS::Object *) { NS::Application *pApp = NS::Application::sharedApplication(); pApp->windows()->object(0)->close(); }); NS::MenuItem *pCloseWindowItem = pWindowMenu->addItem(NS::String::string("Close Window", UTF8StringEncoding), closeWindowCb, NS::String::string("w", UTF8StringEncoding)); pCloseWindowItem->setKeyEquivalentModifierMask(NS::EventModifierFlagCommand); pWindowMenuItem->setSubmenu(pWindowMenu); pMainMenu->addItem(pAppMenuItem); pMainMenu->addItem(pWindowMenuItem); pAppMenuItem->release(); pWindowMenuItem->release(); pAppMenu->release(); pWindowMenu->release(); return pMainMenu->autorelease(); } void MyAppDelegate::applicationWillFinishLaunching(NS::Notification *pNotification) { NS::Menu *pMenu = createMenuBar(); NS::Application *pApp = (NS::Application *)pNotification->object(); pApp->setMainMenu(pMenu); pApp->setActivationPolicy(NS::ActivationPolicy::ActivationPolicyRegular); } void MyAppDelegate::applicationDidFinishLaunching(NS::Notification *pNotification) { NS::Application *pApp = (NS::Application *)pNotification->object(); pApp->activateIgnoringOtherApps(true); } bool MyAppDelegate::applicationShouldTerminateAfterLastWindowClosed(NS::Application *pSender) { return true; } void MyAppDelegate::CreateWindow(int width, int height, const char *title) { CGRect frame = CGRectMake(100.0f, 100.0f, width, height); _pWindow = NS::Window::alloc()->init(frame, NS::WindowStyleMaskClosable | NS::WindowStyleMaskTitled, NS::BackingStoreBuffered, false); NS::View *view = _pWindow->contentView(); view->setWantsLayer(true); view->setLayer((CA::Layer *)CA::MetalLayer::layer()); _pWindow->setTitle(NS::String::string(title, NS::StringEncoding::UTF8StringEncoding)); _pWindow->makeKeyAndOrderFront(NULL); } NS::View *MyAppDelegate::GetContentView() { return _pWindow->contentView(); } NS::Window *MyAppDelegate::GetWindow() { return _pWindow; } AppleWindow::~AppleWindow() { pAppDelegate = NULL; } AppleWindow::AppleWindow(int width, int height, const char *title) : GraphicsWindow(title) { pAppDelegate->CreateWindow(width, height, title); NS::View *nsView = pAppDelegate->GetContentView(); view = nsView; layer = nsView->layer(); } bool AppleWindow::Init() { pSharedApplication = NS::Application::sharedApplication(); pAppDelegate = new MyAppDelegate(); pSharedApplication->setDelegate(pAppDelegate); if(!NS::RunningApplication::currentApplication()->finishedLaunching()) pSharedApplication->finishLaunching(); return true; } void AppleWindow::Resize(int width, int height) { TEST_ERROR("Resize is not implemented"); } extern "C" void *const NSDefaultRunLoopMode; bool AppleWindow::Update() { NS::AutoreleasePool *pAutoreleasePool = NS::AutoreleasePool::alloc()->init(); while(true) { NS::Event *event = pSharedApplication->nextEventMatchingMask( (int)NS::EventMaskAny, NS::Date::distantPast(), (NS::String *)NSDefaultRunLoopMode, true); if(event == NULL) break; pSharedApplication->sendEvent(event); } pAutoreleasePool->release(); return pAppDelegate->GetWindow()->visible(); }