mirror of
https://github.com/scratchfoundation/bgfx.git
synced 2024-12-01 11:56:58 -05:00
631103bfa8
On Android WillSuspend and WillResume maps to focus and DidSuspend and DidResume maps to onPause and onResume. On OSX WillSuspend and DidSuspend maps to resign key, WillResume and DidResumg maps to make key.
762 lines
18 KiB
Text
762 lines
18 KiB
Text
/*
|
|
* Copyright 2011-2015 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 <Cocoa/Cocoa.h>
|
|
|
|
#include <bgfxplatform.h>
|
|
|
|
#include <bx/uint32_t.h>
|
|
#include <bx/thread.h>
|
|
#include <bx/os.h>
|
|
#include <bx/handlealloc.h>
|
|
|
|
@interface AppDelegate : NSObject<NSApplicationDelegate>
|
|
{
|
|
bool terminated;
|
|
}
|
|
|
|
+ (AppDelegate *)sharedDelegate;
|
|
- (id)init;
|
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
|
|
- (bool)applicationHasTerminated;
|
|
|
|
@end
|
|
|
|
@interface Window : NSObject<NSWindowDelegate>
|
|
{
|
|
uint32_t windowCount;
|
|
}
|
|
|
|
+ (Window*)sharedDelegate;
|
|
- (id)init;
|
|
- (void)windowCreated:(NSWindow*)window;
|
|
- (void)windowWillClose:(NSNotification*)notification;
|
|
- (BOOL)windowShouldClose:(NSWindow*)window;
|
|
- (void)windowDidResize:(NSNotification*)notification;
|
|
- (void)windowDidBecomeKey:(NSNotification *)notification;
|
|
- (void)windowDidResignKey:(NSNotification *)notification;
|
|
|
|
@end
|
|
|
|
namespace entry
|
|
{
|
|
static WindowHandle s_defaultWindow = { 0 }; // TODO: Add support for more windows
|
|
static uint8_t s_translateKey[256];
|
|
|
|
struct MainThreadEntry
|
|
{
|
|
int m_argc;
|
|
char** m_argv;
|
|
|
|
static int32_t threadFunc(void* _userData)
|
|
{
|
|
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
|
if ( mainBundle != nil )
|
|
{
|
|
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
|
|
if ( resourcesURL != nil )
|
|
{
|
|
char path[PATH_MAX];
|
|
if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX) )
|
|
{
|
|
chdir(path);
|
|
}
|
|
CFRelease(resourcesURL);
|
|
}
|
|
}
|
|
|
|
MainThreadEntry* self = (MainThreadEntry*)_userData;
|
|
return main(self->m_argc, self->m_argv);
|
|
}
|
|
};
|
|
|
|
struct Context
|
|
{
|
|
Context()
|
|
: m_scrollf(0.0f)
|
|
, m_mx(0)
|
|
, m_my(0)
|
|
, m_scroll(0)
|
|
, m_style(0)
|
|
, m_exit(false)
|
|
, m_fullscreen(false)
|
|
{
|
|
s_translateKey[27] = Key::Esc;
|
|
s_translateKey[uint8_t('\n')] = Key::Return;
|
|
s_translateKey[uint8_t('\t')] = Key::Tab;
|
|
s_translateKey[127] = Key::Backspace;
|
|
s_translateKey[uint8_t(' ')] = Key::Space;
|
|
|
|
s_translateKey[uint8_t('+')] =
|
|
s_translateKey[uint8_t('=')] = Key::Plus;
|
|
s_translateKey[uint8_t('_')] =
|
|
s_translateKey[uint8_t('-')] = Key::Minus;
|
|
|
|
s_translateKey[uint8_t('~')] =
|
|
s_translateKey[uint8_t('`')] = Key::Tilde;
|
|
|
|
s_translateKey[uint8_t(':')] =
|
|
s_translateKey[uint8_t(';')] = Key::Semicolon;
|
|
s_translateKey[uint8_t('"')] =
|
|
s_translateKey[uint8_t('\'')] = Key::Quote;
|
|
|
|
s_translateKey[uint8_t('{')] =
|
|
s_translateKey[uint8_t('[')] = Key::LeftBracket;
|
|
s_translateKey[uint8_t('}')] =
|
|
s_translateKey[uint8_t(']')] = Key::RightBracket;
|
|
|
|
s_translateKey[uint8_t('<')] =
|
|
s_translateKey[uint8_t(',')] = Key::Comma;
|
|
s_translateKey[uint8_t('>')] =
|
|
s_translateKey[uint8_t('.')] = Key::Period;
|
|
s_translateKey[uint8_t('?')] =
|
|
s_translateKey[uint8_t('/')] = Key::Slash;
|
|
s_translateKey[uint8_t('|')] =
|
|
s_translateKey[uint8_t('\\')] = Key::Backslash;
|
|
|
|
s_translateKey[uint8_t('0')] = Key::Key0;
|
|
s_translateKey[uint8_t('1')] = Key::Key1;
|
|
s_translateKey[uint8_t('2')] = Key::Key2;
|
|
s_translateKey[uint8_t('3')] = Key::Key3;
|
|
s_translateKey[uint8_t('4')] = Key::Key4;
|
|
s_translateKey[uint8_t('5')] = Key::Key5;
|
|
s_translateKey[uint8_t('6')] = Key::Key6;
|
|
s_translateKey[uint8_t('7')] = Key::Key7;
|
|
s_translateKey[uint8_t('8')] = Key::Key8;
|
|
s_translateKey[uint8_t('9')] = Key::Key9;
|
|
|
|
for (char ch = 'a'; ch <= 'z'; ++ch)
|
|
{
|
|
s_translateKey[uint8_t(ch)] =
|
|
s_translateKey[uint8_t(ch - ' ')] = Key::KeyA + (ch - 'a');
|
|
}
|
|
}
|
|
|
|
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
|
|
];
|
|
}
|
|
|
|
void getMousePos(int* outX, int* outY)
|
|
{
|
|
WindowHandle handle = { 0 };
|
|
NSWindow* window = m_window[handle.idx];
|
|
NSRect originalFrame = [window frame];
|
|
NSPoint location = [window mouseLocationOutsideOfEventStream];
|
|
NSRect adjustFrame = [window contentRectForFrameRect: originalFrame];
|
|
|
|
int x = location.x;
|
|
int y = (int)adjustFrame.size.height - (int)location.y;
|
|
|
|
// clamp within the range of the window
|
|
|
|
if (x < 0) x = 0;
|
|
if (y < 0) y = 0;
|
|
if (x > (int)adjustFrame.size.width) x = (int)adjustFrame.size.width;
|
|
if (y > (int)adjustFrame.size.height) y = (int)adjustFrame.size.height;
|
|
|
|
*outX = x;
|
|
*outY = y;
|
|
}
|
|
|
|
uint8_t translateModifiers(int flags)
|
|
{
|
|
uint8_t mask = 0;
|
|
|
|
if (flags & NSShiftKeyMask)
|
|
mask |= Modifier::LeftShift | Modifier::RightShift;
|
|
|
|
if (flags & NSAlternateKeyMask)
|
|
mask |= Modifier::LeftAlt | Modifier::RightAlt;
|
|
|
|
if (flags & NSControlKeyMask)
|
|
mask |= Modifier::LeftCtrl | Modifier::RightCtrl;
|
|
|
|
if (flags & NSCommandKeyMask)
|
|
mask |= Modifier::LeftMeta | Modifier::RightMeta;
|
|
|
|
return mask;
|
|
}
|
|
|
|
Key::Enum handleKeyEvent(NSEvent* event, uint8_t* specialKeys, uint8_t* _pressedChar)
|
|
{
|
|
NSString* key = [event charactersIgnoringModifiers];
|
|
unichar keyChar = 0;
|
|
if ([key length] == 0)
|
|
{
|
|
return Key::None;
|
|
}
|
|
|
|
keyChar = [key characterAtIndex:0];
|
|
*_pressedChar = (uint8_t)keyChar;
|
|
|
|
int keyCode = keyChar;
|
|
*specialKeys = translateModifiers([event modifierFlags]);
|
|
|
|
// if this is a unhandled key just return None
|
|
if (keyCode < 256)
|
|
{
|
|
return (Key::Enum)s_translateKey[keyCode];
|
|
}
|
|
|
|
switch (keyCode)
|
|
{
|
|
case NSF1FunctionKey: return Key::F1;
|
|
case NSF2FunctionKey: return Key::F2;
|
|
case NSF3FunctionKey: return Key::F3;
|
|
case NSF4FunctionKey: return Key::F4;
|
|
case NSF5FunctionKey: return Key::F5;
|
|
case NSF6FunctionKey: return Key::F6;
|
|
case NSF7FunctionKey: return Key::F7;
|
|
case NSF8FunctionKey: return Key::F8;
|
|
case NSF9FunctionKey: return Key::F9;
|
|
case NSF10FunctionKey: return Key::F10;
|
|
case NSF11FunctionKey: return Key::F11;
|
|
case NSF12FunctionKey: return Key::F12;
|
|
|
|
case NSLeftArrowFunctionKey: return Key::Left;
|
|
case NSRightArrowFunctionKey: return Key::Right;
|
|
case NSUpArrowFunctionKey: return Key::Up;
|
|
case NSDownArrowFunctionKey: return Key::Down;
|
|
|
|
case NSPageUpFunctionKey: return Key::PageUp;
|
|
case NSPageDownFunctionKey: return Key::PageDown;
|
|
case NSHomeFunctionKey: return Key::Home;
|
|
case NSEndFunctionKey: return Key::End;
|
|
|
|
case NSPrintScreenFunctionKey: return Key::Print;
|
|
}
|
|
|
|
return Key::None;
|
|
}
|
|
|
|
bool dispatchEvent(NSEvent* event)
|
|
{
|
|
if (event)
|
|
{
|
|
NSEventType eventType = [event type];
|
|
|
|
switch (eventType)
|
|
{
|
|
case NSMouseMoved:
|
|
case NSLeftMouseDragged:
|
|
case NSRightMouseDragged:
|
|
case NSOtherMouseDragged:
|
|
{
|
|
getMousePos(&m_mx, &m_my);
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll);
|
|
break;
|
|
}
|
|
|
|
case NSLeftMouseDown:
|
|
{
|
|
// TODO: remove!
|
|
// Command + Left Mouse Button acts as middle! This just a temporary solution!
|
|
// This is becase the average OSX user doesn't have middle mouse click.
|
|
MouseButton::Enum mb = ([event modifierFlags] & NSCommandKeyMask) ? MouseButton::Middle : MouseButton::Left;
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, mb, true);
|
|
break;
|
|
}
|
|
|
|
case NSLeftMouseUp:
|
|
{
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Left, false);
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Middle, false); // TODO: remove!
|
|
break;
|
|
}
|
|
|
|
case NSRightMouseDown:
|
|
{
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Right, true);
|
|
break;
|
|
}
|
|
|
|
case NSRightMouseUp:
|
|
{
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Right, false);
|
|
break;
|
|
}
|
|
|
|
case NSOtherMouseDown:
|
|
{
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Middle, true);
|
|
break;
|
|
}
|
|
|
|
case NSOtherMouseUp:
|
|
{
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Middle, false);
|
|
break;
|
|
}
|
|
|
|
case NSScrollWheel:
|
|
{
|
|
m_scrollf += [event deltaY];
|
|
|
|
m_scroll = (int32_t)m_scrollf;
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll);
|
|
break;
|
|
}
|
|
|
|
case NSKeyDown:
|
|
{
|
|
uint8_t modifiers = 0;
|
|
uint8_t pressedChar[4];
|
|
Key::Enum key = handleKeyEvent(event, &modifiers, &pressedChar[0]);
|
|
|
|
// Returning false means that we take care of the key (instead of the default behavior)
|
|
if (key != Key::None)
|
|
{
|
|
if (key == Key::KeyQ && (modifiers & Modifier::RightMeta) )
|
|
{
|
|
m_eventQueue.postExitEvent();
|
|
}
|
|
else
|
|
{
|
|
enum { ShiftMask = Modifier::LeftShift|Modifier::RightShift };
|
|
m_eventQueue.postCharEvent(s_defaultWindow, 1, pressedChar);
|
|
m_eventQueue.postKeyEvent(s_defaultWindow, key, modifiers, true);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NSKeyUp:
|
|
{
|
|
uint8_t modifiers = 0;
|
|
uint8_t pressedChar[4];
|
|
Key::Enum key = handleKeyEvent(event, &modifiers, &pressedChar[0]);
|
|
|
|
BX_UNUSED(pressedChar);
|
|
|
|
if (key != Key::None)
|
|
{
|
|
m_eventQueue.postKeyEvent(s_defaultWindow, key, modifiers, false);
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
[NSApp sendEvent:event];
|
|
[NSApp updateWindows];
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void windowDidResize()
|
|
{
|
|
WindowHandle handle = { 0 };
|
|
NSWindow* window = m_window[handle.idx];
|
|
NSRect originalFrame = [window frame];
|
|
NSRect rect = [window contentRectForFrameRect: originalFrame];
|
|
uint32_t width = uint32_t(rect.size.width);
|
|
uint32_t height = uint32_t(rect.size.height);
|
|
m_eventQueue.postSizeEvent(handle, width, height);
|
|
|
|
// Make sure mouse button state is 'up' after resize.
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Left, false);
|
|
m_eventQueue.postMouseEvent(s_defaultWindow, m_mx, m_my, m_scroll, MouseButton::Right, false);
|
|
}
|
|
|
|
void windowDidBecomeKey()
|
|
{
|
|
m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::WillResume);
|
|
m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::DidResume);
|
|
}
|
|
|
|
void windowDidResignKey()
|
|
{
|
|
m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::WillSuspend);
|
|
m_eventQueue.postSuspendEvent(s_defaultWindow, Suspend::DidSuspend);
|
|
}
|
|
|
|
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];
|
|
|
|
m_style = 0
|
|
| NSTitledWindowMask
|
|
| NSClosableWindowMask
|
|
| NSMiniaturizableWindowMask
|
|
| NSResizableWindowMask
|
|
;
|
|
|
|
NSRect screenRect = [[NSScreen mainScreen] frame];
|
|
const float centerX = (screenRect.size.width - (float)ENTRY_DEFAULT_WIDTH )*0.5f;
|
|
const float centerY = (screenRect.size.height - (float)ENTRY_DEFAULT_HEIGHT)*0.5f;
|
|
|
|
m_windowAlloc.alloc();
|
|
NSRect rect = NSMakeRect(centerX, centerY, (float)ENTRY_DEFAULT_WIDTH, (float)ENTRY_DEFAULT_HEIGHT);
|
|
NSWindow* window = [[NSWindow alloc]
|
|
initWithContentRect:rect
|
|
styleMask:m_style
|
|
backing:NSBackingStoreBuffered defer:NO
|
|
];
|
|
NSString* appName = [[NSProcessInfo processInfo] processName];
|
|
[window setTitle:appName];
|
|
[window makeKeyAndOrderFront:window];
|
|
[window setAcceptsMouseMovedEvents:YES];
|
|
[window setBackgroundColor:[NSColor blackColor]];
|
|
[[Window sharedDelegate] windowCreated:window];
|
|
|
|
m_window[0] = window;
|
|
m_windowFrame = [window frame];
|
|
|
|
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]) )
|
|
{
|
|
if (bgfx::RenderFrame::Exiting == bgfx::renderFrame() )
|
|
{
|
|
break;
|
|
}
|
|
|
|
while (dispatchEvent(peekEvent() ) )
|
|
{
|
|
}
|
|
}
|
|
|
|
m_eventQueue.postExitEvent();
|
|
|
|
while (bgfx::RenderFrame::NoContext != bgfx::renderFrame() ) {};
|
|
thread.shutdown();
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool isValid(WindowHandle _handle)
|
|
{
|
|
return m_windowAlloc.isValid(_handle.idx);
|
|
}
|
|
|
|
EventQueue m_eventQueue;
|
|
|
|
bx::HandleAllocT<ENTRY_CONFIG_MAX_WINDOWS> m_windowAlloc;
|
|
NSWindow* m_window[ENTRY_CONFIG_MAX_WINDOWS];
|
|
NSRect m_windowFrame;
|
|
|
|
float m_scrollf;
|
|
int32_t m_mx;
|
|
int32_t m_my;
|
|
int32_t m_scroll;
|
|
int32_t m_style;
|
|
bool m_exit;
|
|
bool m_fullscreen;
|
|
};
|
|
|
|
static Context s_ctx;
|
|
|
|
const Event* poll()
|
|
{
|
|
return s_ctx.m_eventQueue.poll();
|
|
}
|
|
|
|
const Event* poll(WindowHandle _handle)
|
|
{
|
|
return s_ctx.m_eventQueue.poll(_handle);
|
|
}
|
|
|
|
void release(const Event* _event)
|
|
{
|
|
s_ctx.m_eventQueue.release(_event);
|
|
}
|
|
|
|
WindowHandle createWindow(int32_t _x, int32_t _y, uint32_t _width, uint32_t _height, uint32_t _flags, const char* _title)
|
|
{
|
|
BX_UNUSED(_x, _y, _width, _height, _flags, _title);
|
|
WindowHandle handle = { UINT16_MAX };
|
|
return handle;
|
|
}
|
|
|
|
void destroyWindow(WindowHandle _handle)
|
|
{
|
|
if (s_ctx.isValid(_handle) )
|
|
{
|
|
dispatch_async(dispatch_get_main_queue()
|
|
, ^{
|
|
[s_ctx.m_window[_handle.idx] performClose: nil];
|
|
});
|
|
}
|
|
}
|
|
|
|
void setWindowPos(WindowHandle _handle, int32_t _x, int32_t _y)
|
|
{
|
|
if (s_ctx.isValid(_handle) )
|
|
{
|
|
NSWindow* window = s_ctx.m_window[_handle.idx];
|
|
NSScreen* screen = [window screen];
|
|
|
|
NSRect screenRect = [screen frame];
|
|
CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
|
|
|
|
NSPoint position = { float(_x), screenRect.size.height - menuBarHeight - float(_y) };
|
|
|
|
dispatch_async(dispatch_get_main_queue()
|
|
, ^{
|
|
[window setFrameTopLeftPoint: position];
|
|
});
|
|
}
|
|
}
|
|
|
|
void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
|
|
{
|
|
if (s_ctx.isValid(_handle) )
|
|
{
|
|
NSSize size = { float(_width), float(_height) };
|
|
dispatch_async(dispatch_get_main_queue()
|
|
, ^{
|
|
[s_ctx.m_window[_handle.idx] setContentSize: size];
|
|
});
|
|
}
|
|
}
|
|
|
|
void setWindowTitle(WindowHandle _handle, const char* _title)
|
|
{
|
|
if (s_ctx.isValid(_handle) )
|
|
{
|
|
NSString* title = [[NSString alloc] initWithCString:_title encoding:1];
|
|
dispatch_async(dispatch_get_main_queue()
|
|
, ^{
|
|
[s_ctx.m_window[_handle.idx] setTitle: title];
|
|
});
|
|
[title release];
|
|
}
|
|
}
|
|
|
|
void toggleWindowFrame(WindowHandle _handle)
|
|
{
|
|
if (s_ctx.isValid(_handle) )
|
|
{
|
|
s_ctx.m_style ^= NSTitledWindowMask;
|
|
dispatch_async(dispatch_get_main_queue()
|
|
, ^{
|
|
[s_ctx.m_window[_handle.idx] setStyleMask: s_ctx.m_style];
|
|
});
|
|
}
|
|
}
|
|
|
|
void toggleFullscreen(WindowHandle _handle)
|
|
{
|
|
if (s_ctx.isValid(_handle) )
|
|
{
|
|
NSWindow* window = s_ctx.m_window[_handle.idx];
|
|
NSScreen* screen = [window screen];
|
|
NSRect screenRect = [screen frame];
|
|
|
|
if (!s_ctx.m_fullscreen)
|
|
{
|
|
s_ctx.m_style &= ~NSTitledWindowMask;
|
|
dispatch_async(dispatch_get_main_queue()
|
|
, ^{
|
|
[NSMenu setMenuBarVisible: false];
|
|
[window setStyleMask: s_ctx.m_style];
|
|
[window setFrame:screenRect display:YES];
|
|
});
|
|
|
|
s_ctx.m_fullscreen = true;
|
|
}
|
|
else
|
|
{
|
|
s_ctx.m_style |= NSTitledWindowMask;
|
|
dispatch_async(dispatch_get_main_queue()
|
|
, ^{
|
|
[NSMenu setMenuBarVisible: true];
|
|
[window setStyleMask: s_ctx.m_style];
|
|
[window setFrame:s_ctx.m_windowFrame display:YES];
|
|
});
|
|
|
|
s_ctx.m_fullscreen = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void setMouseLock(WindowHandle _handle, bool _lock)
|
|
{
|
|
BX_UNUSED(_handle, _lock);
|
|
}
|
|
|
|
} // namespace entry
|
|
|
|
@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
|
|
|
|
@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;
|
|
}
|
|
|
|
- (void)windowWillClose:(NSNotification*)notification
|
|
{
|
|
BX_UNUSED(notification);
|
|
}
|
|
|
|
- (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;
|
|
}
|
|
|
|
- (void)windowDidResize:(NSNotification*)notification
|
|
{
|
|
BX_UNUSED(notification);
|
|
using namespace entry;
|
|
s_ctx.windowDidResize();
|
|
}
|
|
|
|
- (void)windowDidBecomeKey:(NSNotification*)notification
|
|
{
|
|
BX_UNUSED(notification);
|
|
using namespace entry;
|
|
s_ctx.windowDidBecomeKey();
|
|
}
|
|
|
|
- (void)windowDidResignKey:(NSNotification*)notification
|
|
{
|
|
BX_UNUSED(notification);
|
|
using namespace entry;
|
|
s_ctx.windowDidResignKey();
|
|
}
|
|
|
|
@end
|
|
|
|
int main(int _argc, char** _argv)
|
|
{
|
|
using namespace entry;
|
|
return s_ctx.run(_argc, _argv);
|
|
}
|
|
|
|
#endif // BX_PLATFORM_OSX
|