/* * Copyright 2011-2014 Branimir Karadzic. All rights reserved. * License: http://www.opensource.org/licenses/BSD-2-Clause */ #include "entry_p.h" #if ENTRY_CONFIG_USE_NATIVE && BX_PLATFORM_OSX #import #include #include #include #include #define DEFAULT_WIDTH 1280 #define DEFAULT_HEIGHT 720 @interface AppDelegate : NSObject { bool terminated; } + (AppDelegate *)sharedDelegate; - (id)init; - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; - (bool)applicationHasTerminated; @end @implementation AppDelegate + (AppDelegate *)sharedDelegate { static id delegate = [AppDelegate new]; return delegate; } - (id)init { self = [super init]; if (nil == self) { return nil; } self->terminated = false; return self; } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { BX_UNUSED(sender); self->terminated = true; return NSTerminateCancel; } - (bool)applicationHasTerminated { return self->terminated; } @end @interface Window : NSObject { unsigned int windowCount; } + (Window *)sharedDelegate; - (id)init; - (void)windowCreated:(NSWindow *)window; - (BOOL)windowShouldClose:(NSWindow *)window; @end @implementation Window + (Window *)sharedDelegate { static id windowDelegate = [Window new]; return windowDelegate; } - (id)init { self = [super init]; if (nil == self) { return nil; } self->windowCount = 0; return self; } - (void)windowCreated:(NSWindow *)window { assert(window); [window setDelegate:self]; assert(self->windowCount < ~0u); self->windowCount += 1; } - (BOOL)windowShouldClose:(NSWindow *)window { assert(window); [window setDelegate:nil]; assert(self->windowCount); self->windowCount -= 1; if (self->windowCount == 0) { [NSApp terminate:self]; return false; } return true; } @end namespace entry { struct MainThreadEntry { int m_argc; char** m_argv; static int32_t threadFunc(void* _userData) { MainThreadEntry* self = (MainThreadEntry*)_userData; return main(self->m_argc, self->m_argv); } }; struct Context { Context() : m_exit(false) { } NSEvent* WaitEvent() { return [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] // wait for event inMode:NSDefaultRunLoopMode dequeue:YES ]; } NSEvent* PeekEvent() { return [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] // do not wait for event inMode:NSDefaultRunLoopMode dequeue:YES ]; } bool DispatchEvent(NSEvent* event) { if (event) { [NSApp sendEvent:event]; [NSApp updateWindows]; return true; } return false; } int32_t run(int _argc, char** _argv) { [NSApplication sharedApplication]; id dg = [AppDelegate sharedDelegate]; [NSApp setDelegate:dg]; [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; [NSApp activateIgnoringOtherApps:YES]; [NSApp finishLaunching]; [[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationWillFinishLaunchingNotification object:NSApp]; [[NSNotificationCenter defaultCenter] postNotificationName:NSApplicationDidFinishLaunchingNotification object:NSApp]; id quitMenuItem = [NSMenuItem new]; [quitMenuItem initWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"]; id appMenu = [NSMenu new]; [appMenu addItem:quitMenuItem]; id appMenuItem = [NSMenuItem new]; [appMenuItem setSubmenu:appMenu]; id menubar = [[NSMenu new] autorelease]; [menubar addItem:appMenuItem]; [NSApp setMainMenu:menubar]; NSRect rect = NSMakeRect(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT); NSWindow* window = [NSWindow alloc]; [window initWithContentRect:rect styleMask:0 |NSTitledWindowMask |NSClosableWindowMask |NSMiniaturizableWindowMask |NSResizableWindowMask backing:NSBackingStoreBuffered defer:NO ]; NSString* appName = [[NSProcessInfo processInfo] processName]; [window setTitle:appName]; [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; [window makeKeyAndOrderFront:window]; [window setContentView:nil]; [[Window sharedDelegate] windowCreated:window]; bgfx::osxSetNSWindow(window); MainThreadEntry mte; mte.m_argc = _argc; mte.m_argv = _argv; bx::Thread thread; thread.init(mte.threadFunc, &mte); while (!(m_exit = [dg applicationHasTerminated]) ) { //DispatchEvent(WaitEvent() ); if (bgfx::RenderFrame::Exiting == bgfx::renderFrame() ) { break; } while (DispatchEvent(PeekEvent() ) ) {}; } m_eventQueue.postExitEvent(); while (bgfx::RenderFrame::NoContext != bgfx::renderFrame() ) {}; thread.shutdown(); return 0; } EventQueue m_eventQueue; bool m_exit; }; static Context s_ctx; const Event* poll() { return s_ctx.m_eventQueue.poll(); } void release(const Event* _event) { s_ctx.m_eventQueue.release(_event); } void setWindowSize(uint32_t _width, uint32_t _height) { BX_UNUSED(_width, _height); } void setWindowTitle(const char* _title) { BX_UNUSED(_title); } void toggleWindowFrame() { } void setMouseLock(bool _lock) { BX_UNUSED(_lock); } } // namespace entry int main(int _argc, char** _argv) { using namespace entry; return s_ctx.run(_argc, _argv); } #endif // BX_PLATFORM_OSX