entry_osx.mm 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /*
  2. * Copyright 2011-2017 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include "entry_p.h"
  6. #if ENTRY_CONFIG_USE_NATIVE && BX_PLATFORM_OSX
  7. #import <Cocoa/Cocoa.h>
  8. #include <bgfx/platform.h>
  9. #include <bx/uint32_t.h>
  10. #include <bx/thread.h>
  11. #include <bx/os.h>
  12. #include <bx/handlealloc.h>
  13. @interface AppDelegate : NSObject<NSApplicationDelegate>
  14. {
  15. bool terminated;
  16. }
  17. + (AppDelegate *)sharedDelegate;
  18. - (id)init;
  19. - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
  20. - (bool)applicationHasTerminated;
  21. @end
  22. @interface Window : NSObject<NSWindowDelegate>
  23. {
  24. uint32_t windowCount;
  25. }
  26. + (Window*)sharedDelegate;
  27. - (id)init;
  28. - (void)windowCreated:(NSWindow*)window;
  29. - (void)windowWillClose:(NSNotification*)notification;
  30. - (BOOL)windowShouldClose:(NSWindow*)window;
  31. - (void)windowDidResize:(NSNotification*)notification;
  32. - (void)windowDidBecomeKey:(NSNotification *)notification;
  33. - (void)windowDidResignKey:(NSNotification *)notification;
  34. @end
  35. namespace entry
  36. {
  37. ///
  38. inline void osxSetNSWindow(void* _window, void* _nsgl = NULL)
  39. {
  40. bgfx::PlatformData pd;
  41. pd.ndt = NULL;
  42. pd.nwh = _window;
  43. pd.context = _nsgl;
  44. pd.backBuffer = NULL;
  45. pd.backBufferDS = NULL;
  46. bgfx::setPlatformData(pd);
  47. }
  48. static WindowHandle s_defaultWindow = { 0 };
  49. static uint8_t s_translateKey[256];
  50. struct MainThreadEntry
  51. {
  52. int m_argc;
  53. char** m_argv;
  54. static int32_t threadFunc(void* _userData)
  55. {
  56. CFBundleRef mainBundle = CFBundleGetMainBundle();
  57. if ( mainBundle != nil )
  58. {
  59. CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
  60. if ( resourcesURL != nil )
  61. {
  62. char path[PATH_MAX];
  63. if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX) )
  64. {
  65. chdir(path);
  66. }
  67. CFRelease(resourcesURL);
  68. }
  69. }
  70. MainThreadEntry* self = (MainThreadEntry*)_userData;
  71. return main(self->m_argc, self->m_argv);
  72. }
  73. };
  74. struct Context
  75. {
  76. Context()
  77. : m_scrollf(0.0f)
  78. , m_mx(0)
  79. , m_my(0)
  80. , m_scroll(0)
  81. , m_style(0)
  82. , m_exit(false)
  83. , m_fullscreen(false)
  84. {
  85. s_translateKey[27] = Key::Esc;
  86. s_translateKey[uint8_t('\n')] = Key::Return;
  87. s_translateKey[uint8_t('\t')] = Key::Tab;
  88. s_translateKey[127] = Key::Backspace;
  89. s_translateKey[uint8_t(' ')] = Key::Space;
  90. s_translateKey[uint8_t('+')] =
  91. s_translateKey[uint8_t('=')] = Key::Plus;
  92. s_translateKey[uint8_t('_')] =
  93. s_translateKey[uint8_t('-')] = Key::Minus;
  94. s_translateKey[uint8_t('~')] =
  95. s_translateKey[uint8_t('`')] = Key::Tilde;
  96. s_translateKey[uint8_t(':')] =
  97. s_translateKey[uint8_t(';')] = Key::Semicolon;
  98. s_translateKey[uint8_t('"')] =
  99. s_translateKey[uint8_t('\'')] = Key::Quote;
  100. s_translateKey[uint8_t('{')] =
  101. s_translateKey[uint8_t('[')] = Key::LeftBracket;
  102. s_translateKey[uint8_t('}')] =
  103. s_translateKey[uint8_t(']')] = Key::RightBracket;
  104. s_translateKey[uint8_t('<')] =
  105. s_translateKey[uint8_t(',')] = Key::Comma;
  106. s_translateKey[uint8_t('>')] =
  107. s_translateKey[uint8_t('.')] = Key::Period;
  108. s_translateKey[uint8_t('?')] =
  109. s_translateKey[uint8_t('/')] = Key::Slash;
  110. s_translateKey[uint8_t('|')] =
  111. s_translateKey[uint8_t('\\')] = Key::Backslash;
  112. s_translateKey[uint8_t('0')] = Key::Key0;
  113. s_translateKey[uint8_t('1')] = Key::Key1;
  114. s_translateKey[uint8_t('2')] = Key::Key2;
  115. s_translateKey[uint8_t('3')] = Key::Key3;
  116. s_translateKey[uint8_t('4')] = Key::Key4;
  117. s_translateKey[uint8_t('5')] = Key::Key5;
  118. s_translateKey[uint8_t('6')] = Key::Key6;
  119. s_translateKey[uint8_t('7')] = Key::Key7;
  120. s_translateKey[uint8_t('8')] = Key::Key8;
  121. s_translateKey[uint8_t('9')] = Key::Key9;
  122. for (char ch = 'a'; ch <= 'z'; ++ch)
  123. {
  124. s_translateKey[uint8_t(ch)] =
  125. s_translateKey[uint8_t(ch - ' ')] = Key::KeyA + (ch - 'a');
  126. }
  127. }
  128. NSEvent* waitEvent()
  129. {
  130. return [NSApp
  131. nextEventMatchingMask:NSAnyEventMask
  132. untilDate:[NSDate distantFuture] // wait for event
  133. inMode:NSDefaultRunLoopMode
  134. dequeue:YES
  135. ];
  136. }
  137. NSEvent* peekEvent()
  138. {
  139. return [NSApp
  140. nextEventMatchingMask:NSAnyEventMask
  141. untilDate:[NSDate distantPast] // do not wait for event
  142. inMode:NSDefaultRunLoopMode
  143. dequeue:YES
  144. ];
  145. }
  146. void getMousePos(int* outX, int* outY)
  147. {
  148. WindowHandle handle = { 0 };
  149. NSWindow* window = m_window[handle.idx];
  150. NSRect originalFrame = [window frame];
  151. NSPoint location = [window mouseLocationOutsideOfEventStream];
  152. NSRect adjustFrame = [window contentRectForFrameRect: originalFrame];
  153. int x = location.x;
  154. int y = (int)adjustFrame.size.height - (int)location.y;
  155. // clamp within the range of the window
  156. if (x < 0) x = 0;
  157. if (y < 0) y = 0;
  158. if (x > (int)adjustFrame.size.width) x = (int)adjustFrame.size.width;
  159. if (y > (int)adjustFrame.size.height) y = (int)adjustFrame.size.height;
  160. *outX = x;
  161. *outY = y;
  162. }
  163. uint8_t translateModifiers(int flags)
  164. {
  165. uint8_t mask = 0;
  166. if (flags & NSShiftKeyMask)
  167. mask |= Modifier::LeftShift | Modifier::RightShift;
  168. if (flags & NSAlternateKeyMask)
  169. mask |= Modifier::LeftAlt | Modifier::RightAlt;
  170. if (flags & NSControlKeyMask)
  171. mask |= Modifier::LeftCtrl | Modifier::RightCtrl;
  172. if (flags & NSCommandKeyMask)
  173. mask |= Modifier::LeftMeta | Modifier::RightMeta;
  174. return mask;
  175. }
  176. Key::Enum handleKeyEvent(NSEvent* event, uint8_t* specialKeys, uint8_t* _pressedChar)
  177. {
  178. NSString* key = [event charactersIgnoringModifiers];
  179. unichar keyChar = 0;
  180. if ([key length] == 0)
  181. {
  182. return Key::None;
  183. }
  184. keyChar = [key characterAtIndex:0];
  185. *_pressedChar = (uint8_t)keyChar;
  186. int keyCode = keyChar;
  187. *specialKeys = translateModifiers([event modifierFlags]);
  188. // if this is a unhandled key just return None
  189. if (keyCode < 256)
  190. {
  191. return (Key::Enum)s_translateKey[keyCode];
  192. }
  193. switch (keyCode)
  194. {
  195. case NSF1FunctionKey: return Key::F1;
  196. case NSF2FunctionKey: return Key::F2;
  197. case NSF3FunctionKey: return Key::F3;
  198. case NSF4FunctionKey: return Key::F4;
  199. case NSF5FunctionKey: return Key::F5;
  200. case NSF6FunctionKey: return Key::F6;
  201. case NSF7FunctionKey: return Key::F7;
  202. case NSF8FunctionKey: return Key::F8;
  203. case NSF9FunctionKey: return Key::F9;
  204. case NSF10FunctionKey: return Key::F10;
  205. case NSF11FunctionKey: return Key::F11;
  206. case NSF12FunctionKey: return Key::F12;
  207. case NSLeftArrowFunctionKey: return Key::Left;
  208. case NSRightArrowFunctionKey: return Key::Right;
  209. case NSUpArrowFunctionKey: return Key::Up;
  210. case NSDownArrowFunctionKey: return Key::Down;
  211. case NSPageUpFunctionKey: return Key::PageUp;
  212. case NSPageDownFunctionKey: return Key::PageDown;
  213. case NSHomeFunctionKey: return Key::Home;
  214. case NSEndFunctionKey: return Key::End;
  215. case NSPrintScreenFunctionKey: return Key::Print;
  216. }
  217. return Key::None;
  218. }
  219. bool dispatchEvent(NSEvent* event)
  220. {
  221. if (event)
  222. {
  223. NSEventType eventType = [event type];
  224. switch (eventType)
  225. {
  226. case NSMouseMoved:
  227. case NSLeftMouseDragged:
  228. case NSRightMouseDragged:
  229. case NSOtherMouseDragged:
  230. {
  231. getMousePos(&m_mx, &m_my);
  232. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll);
  233. break;
  234. }
  235. case NSLeftMouseDown:
  236. {
  237. // Command + Left Mouse Button acts as middle! This just a temporary solution!
  238. // This is because the average OSX user doesn't have middle mouse click.
  239. MouseButton::Enum mb = ([event modifierFlags] & NSCommandKeyMask) ? MouseButton::Middle : MouseButton::Left;
  240. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, mb, true);
  241. break;
  242. }
  243. case NSLeftMouseUp:
  244. {
  245. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Left, false);
  246. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Middle, false); // TODO: remove!
  247. break;
  248. }
  249. case NSRightMouseDown:
  250. {
  251. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Right, true);
  252. break;
  253. }
  254. case NSRightMouseUp:
  255. {
  256. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Right, false);
  257. break;
  258. }
  259. case NSOtherMouseDown:
  260. {
  261. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Middle, true);
  262. break;
  263. }
  264. case NSOtherMouseUp:
  265. {
  266. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Middle, false);
  267. break;
  268. }
  269. case NSScrollWheel:
  270. {
  271. m_scrollf += [event deltaY];
  272. m_scroll = (int32_t)m_scrollf;
  273. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll);
  274. break;
  275. }
  276. case NSKeyDown:
  277. {
  278. uint8_t modifiers = 0;
  279. uint8_t pressedChar[4];
  280. Key::Enum key = handleKeyEvent(event, &modifiers, &pressedChar[0]);
  281. // Returning false means that we take care of the key (instead of the default behavior)
  282. if (key != Key::None)
  283. {
  284. if (key == Key::KeyQ && (modifiers & Modifier::RightMeta) )
  285. {
  286. m_eventQueue.postExitEvent();
  287. }
  288. else
  289. {
  290. enum { ShiftMask = Modifier::LeftShift|Modifier::RightShift };
  291. m_eventQueue.postCharEvent(s_defaultWindow, 1, pressedChar);
  292. m_eventQueue.postKeyEvent(s_defaultWindow, key, modifiers, true);
  293. return false;
  294. }
  295. }
  296. break;
  297. }
  298. case NSKeyUp:
  299. {
  300. uint8_t modifiers = 0;
  301. uint8_t pressedChar[4];
  302. Key::Enum key = handleKeyEvent(event, &modifiers, &pressedChar[0]);
  303. BX_UNUSED(pressedChar);
  304. if (key != Key::None)
  305. {
  306. m_eventQueue.postKeyEvent(s_defaultWindow, key, modifiers, false);
  307. return false;
  308. }
  309. break;
  310. }
  311. }
  312. [NSApp sendEvent:event];
  313. [NSApp updateWindows];
  314. return true;
  315. }
  316. return false;
  317. }
  318. void windowDidResize()
  319. {
  320. WindowHandle handle = { 0 };
  321. NSWindow* window = m_window[handle.idx];
  322. NSRect originalFrame = [window frame];
  323. NSRect rect = [window contentRectForFrameRect: originalFrame];
  324. uint32_t width = uint32_t(rect.size.width);
  325. uint32_t height = uint32_t(rect.size.height);
  326. m_eventQueue.postSizeEvent(handle, width, height);
  327. // Make sure mouse button state is 'up' after resize.
  328. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Left, false);
  329. m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Right, false);
  330. }
  331. void windowDidBecomeKey()
  332. {
  333. m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::WillResume);
  334. m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::DidResume);
  335. }
  336. void windowDidResignKey()
  337. {
  338. m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::WillSuspend);
  339. m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::DidSuspend);
  340. }
  341. int32_t run(int _argc, char** _argv)
  342. {
  343. [NSApplication sharedApplication];
  344. id dg = [AppDelegate sharedDelegate];
  345. [NSApp setDelegate:dg];
  346. [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
  347. [NSApp activateIgnoringOtherApps:YES];
  348. [NSApp finishLaunching];
  349. [[NSNotificationCenter defaultCenter]
  350. postNotificationName:NSApplicationWillFinishLaunchingNotification
  351. object:NSApp];
  352. [[NSNotificationCenter defaultCenter]
  353. postNotificationName:NSApplicationDidFinishLaunchingNotification
  354. object:NSApp];
  355. id quitMenuItem = [NSMenuItem new];
  356. [quitMenuItem
  357. initWithTitle:@"Quit"
  358. action:@selector(terminate:)
  359. keyEquivalent:@"q"];
  360. id appMenu = [NSMenu new];
  361. [appMenu addItem:quitMenuItem];
  362. id appMenuItem = [NSMenuItem new];
  363. [appMenuItem setSubmenu:appMenu];
  364. id menubar = [[NSMenu new] autorelease];
  365. [menubar addItem:appMenuItem];
  366. [NSApp setMainMenu:menubar];
  367. m_style = 0
  368. | NSTitledWindowMask
  369. | NSClosableWindowMask
  370. | NSMiniaturizableWindowMask
  371. | NSResizableWindowMask
  372. ;
  373. NSRect screenRect = [[NSScreen mainScreen] frame];
  374. const float centerX = (screenRect.size.width - (float)ENTRY_DEFAULT_WIDTH )*0.5f;
  375. const float centerY = (screenRect.size.height - (float)ENTRY_DEFAULT_HEIGHT)*0.5f;
  376. m_windowAlloc.alloc();
  377. NSRect rect = NSMakeRect(centerX, centerY, ENTRY_DEFAULT_WIDTH, ENTRY_DEFAULT_HEIGHT);
  378. NSWindow* window = [[NSWindow alloc]
  379. initWithContentRect:rect
  380. styleMask:m_style
  381. backing:NSBackingStoreBuffered defer:NO
  382. ];
  383. NSString* appName = [[NSProcessInfo processInfo] processName];
  384. [window setTitle:appName];
  385. [window makeKeyAndOrderFront:window];
  386. [window setAcceptsMouseMovedEvents:YES];
  387. [window setBackgroundColor:[NSColor blackColor]];
  388. [[Window sharedDelegate] windowCreated:window];
  389. m_window[0] = window;
  390. m_windowFrame = [window frame];
  391. osxSetNSWindow(window);
  392. MainThreadEntry mte;
  393. mte.m_argc = _argc;
  394. mte.m_argv = _argv;
  395. bx::Thread thread;
  396. thread.init(mte.threadFunc, &mte);
  397. WindowHandle handle = { 0 };
  398. m_eventQueue.postSizeEvent(handle, ENTRY_DEFAULT_WIDTH, ENTRY_DEFAULT_HEIGHT);
  399. while (!(m_exit = [dg applicationHasTerminated]) )
  400. {
  401. @autoreleasepool
  402. {
  403. if (bgfx::RenderFrame::Exiting == bgfx::renderFrame() )
  404. {
  405. break;
  406. }
  407. }
  408. while (dispatchEvent(peekEvent() ) )
  409. {
  410. }
  411. }
  412. m_eventQueue.postExitEvent();
  413. while (bgfx::RenderFrame::NoContext != bgfx::renderFrame() ) {};
  414. thread.shutdown();
  415. return 0;
  416. }
  417. bool isValid(WindowHandle _handle)
  418. {
  419. return m_windowAlloc.isValid(_handle.idx);
  420. }
  421. EventQueue m_eventQueue;
  422. bx::HandleAllocT<ENTRY_CONFIG_MAX_WINDOWS> m_windowAlloc;
  423. NSWindow* m_window[ENTRY_CONFIG_MAX_WINDOWS];
  424. NSRect m_windowFrame;
  425. float m_scrollf;
  426. int32_t m_mx;
  427. int32_t m_my;
  428. int32_t m_scroll;
  429. int32_t m_style;
  430. bool m_exit;
  431. bool m_fullscreen;
  432. };
  433. static Context s_ctx;
  434. const Event* poll()
  435. {
  436. return s_ctx.m_eventQueue.poll();
  437. }
  438. const Event* poll(WindowHandle _handle)
  439. {
  440. return s_ctx.m_eventQueue.poll(_handle);
  441. }
  442. void release(const Event* _event)
  443. {
  444. s_ctx.m_eventQueue.release(_event);
  445. }
  446. WindowHandle createWindow(int32_t _x, int32_t _y, uint32_t _width, uint32_t _height, uint32_t _flags, const char* _title)
  447. {
  448. BX_UNUSED(_x, _y, _width, _height, _flags, _title);
  449. WindowHandle handle = { UINT16_MAX };
  450. return handle;
  451. }
  452. void destroyWindow(WindowHandle _handle)
  453. {
  454. if (s_ctx.isValid(_handle) )
  455. {
  456. dispatch_async(dispatch_get_main_queue()
  457. , ^{
  458. [s_ctx.m_window[_handle.idx] performClose: nil];
  459. });
  460. }
  461. }
  462. void setWindowPos(WindowHandle _handle, int32_t _x, int32_t _y)
  463. {
  464. if (s_ctx.isValid(_handle) )
  465. {
  466. NSWindow* window = s_ctx.m_window[_handle.idx];
  467. NSScreen* screen = [window screen];
  468. NSRect screenRect = [screen frame];
  469. CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
  470. NSPoint position = { float(_x), screenRect.size.height - menuBarHeight - float(_y) };
  471. dispatch_async(dispatch_get_main_queue()
  472. , ^{
  473. [window setFrameTopLeftPoint: position];
  474. });
  475. }
  476. }
  477. void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
  478. {
  479. if (s_ctx.isValid(_handle) )
  480. {
  481. NSSize size = { float(_width), float(_height) };
  482. dispatch_async(dispatch_get_main_queue()
  483. , ^{
  484. [s_ctx.m_window[_handle.idx] setContentSize: size];
  485. });
  486. }
  487. }
  488. void setWindowTitle(WindowHandle _handle, const char* _title)
  489. {
  490. if (s_ctx.isValid(_handle) )
  491. {
  492. NSString* title = [[NSString alloc] initWithCString:_title encoding:1];
  493. dispatch_async(dispatch_get_main_queue()
  494. , ^{
  495. [s_ctx.m_window[_handle.idx] setTitle: title];
  496. });
  497. [title release];
  498. }
  499. }
  500. void toggleWindowFrame(WindowHandle _handle)
  501. {
  502. if (s_ctx.isValid(_handle) )
  503. {
  504. s_ctx.m_style ^= NSTitledWindowMask;
  505. dispatch_async(dispatch_get_main_queue()
  506. , ^{
  507. [s_ctx.m_window[_handle.idx] setStyleMask: s_ctx.m_style];
  508. });
  509. }
  510. }
  511. void toggleFullscreen(WindowHandle _handle)
  512. {
  513. if (s_ctx.isValid(_handle) )
  514. {
  515. NSWindow* window = s_ctx.m_window[_handle.idx];
  516. NSScreen* screen = [window screen];
  517. NSRect screenRect = [screen frame];
  518. if (!s_ctx.m_fullscreen)
  519. {
  520. s_ctx.m_style &= ~NSTitledWindowMask;
  521. dispatch_async(dispatch_get_main_queue()
  522. , ^{
  523. [NSMenu setMenuBarVisible: false];
  524. [window setStyleMask: s_ctx.m_style];
  525. [window setFrame:screenRect display:YES];
  526. });
  527. s_ctx.m_fullscreen = true;
  528. }
  529. else
  530. {
  531. s_ctx.m_style |= NSTitledWindowMask;
  532. dispatch_async(dispatch_get_main_queue()
  533. , ^{
  534. [NSMenu setMenuBarVisible: true];
  535. [window setStyleMask: s_ctx.m_style];
  536. [window setFrame:s_ctx.m_windowFrame display:YES];
  537. });
  538. s_ctx.m_fullscreen = false;
  539. }
  540. }
  541. }
  542. void setMouseLock(WindowHandle _handle, bool _lock)
  543. {
  544. BX_UNUSED(_handle, _lock);
  545. }
  546. } // namespace entry
  547. @implementation AppDelegate
  548. + (AppDelegate *)sharedDelegate
  549. {
  550. static id delegate = [AppDelegate new];
  551. return delegate;
  552. }
  553. - (id)init
  554. {
  555. self = [super init];
  556. if (nil == self)
  557. {
  558. return nil;
  559. }
  560. self->terminated = false;
  561. return self;
  562. }
  563. - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
  564. {
  565. BX_UNUSED(sender);
  566. self->terminated = true;
  567. return NSTerminateCancel;
  568. }
  569. - (bool)applicationHasTerminated
  570. {
  571. return self->terminated;
  572. }
  573. @end
  574. @implementation Window
  575. + (Window*)sharedDelegate
  576. {
  577. static id windowDelegate = [Window new];
  578. return windowDelegate;
  579. }
  580. - (id)init
  581. {
  582. self = [super init];
  583. if (nil == self)
  584. {
  585. return nil;
  586. }
  587. self->windowCount = 0;
  588. return self;
  589. }
  590. - (void)windowCreated:(NSWindow*)window
  591. {
  592. assert(window);
  593. [window setDelegate:self];
  594. assert(self->windowCount < ~0u);
  595. self->windowCount += 1;
  596. }
  597. - (void)windowWillClose:(NSNotification*)notification
  598. {
  599. BX_UNUSED(notification);
  600. }
  601. - (BOOL)windowShouldClose:(NSWindow*)window
  602. {
  603. assert(window);
  604. [window setDelegate:nil];
  605. assert(self->windowCount);
  606. self->windowCount -= 1;
  607. if (self->windowCount == 0)
  608. {
  609. [NSApp terminate:self];
  610. return false;
  611. }
  612. return true;
  613. }
  614. - (void)windowDidResize:(NSNotification*)notification
  615. {
  616. BX_UNUSED(notification);
  617. using namespace entry;
  618. s_ctx.windowDidResize();
  619. }
  620. - (void)windowDidBecomeKey:(NSNotification*)notification
  621. {
  622. BX_UNUSED(notification);
  623. using namespace entry;
  624. s_ctx.windowDidBecomeKey();
  625. }
  626. - (void)windowDidResignKey:(NSNotification*)notification
  627. {
  628. BX_UNUSED(notification);
  629. using namespace entry;
  630. s_ctx.windowDidResignKey();
  631. }
  632. @end
  633. int main(int _argc, char** _argv)
  634. {
  635. using namespace entry;
  636. return s_ctx.run(_argc, _argv);
  637. }
  638. #endif // BX_PLATFORM_OSX