bgfx/examples/common/entry/entry_osx.mm

844 lines
21 KiB
Plaintext
Raw Normal View History

/*
2023-01-14 21:05:12 +03:00
* Copyright 2011-2023 Branimir Karadzic. All rights reserved.
2022-01-15 22:59:06 +03:00
* License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
*/
2013-08-15 08:08:46 +04:00
#include "entry_p.h"
2013-08-15 08:08:46 +04:00
#if ENTRY_CONFIG_USE_NATIVE && BX_PLATFORM_OSX
2013-08-08 09:50:01 +04:00
#import <Cocoa/Cocoa.h>
#include <bgfx/platform.h>
2013-08-08 10:11:20 +04:00
2013-08-08 09:50:01 +04:00
#include <bx/uint32_t.h>
#include <bx/thread.h>
#include <bx/os.h>
2014-10-02 07:25:56 +04:00
#include <bx/handlealloc.h>
2013-07-22 08:53:20 +04:00
@interface AppDelegate : NSObject<NSApplicationDelegate>
{
bool terminated;
}
2013-07-22 08:53:20 +04:00
+ (AppDelegate *)sharedDelegate;
- (id)init;
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
- (bool)applicationHasTerminated;
2013-07-22 08:53:20 +04:00
@end
2013-07-22 08:53:20 +04:00
@interface Window : NSObject<NSWindowDelegate>
{
}
2013-07-22 08:53:20 +04:00
2014-10-02 07:25:56 +04:00
+ (Window*)sharedDelegate;
- (id)init;
2014-10-02 07:25:56 +04:00
- (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 uint8_t s_translateKey[256];
struct MainThreadEntry
{
int m_argc;
2017-06-30 08:30:35 +03:00
const char* const* m_argv;
2013-07-22 01:44:53 +04:00
2017-11-05 01:49:02 +03:00
static int32_t threadFunc(bx::Thread* _thread, void* _userData)
{
2017-11-05 01:25:11 +03:00
BX_UNUSED(_thread);
2015-02-04 09:24:40 +03:00
CFBundleRef mainBundle = CFBundleGetMainBundle();
2017-11-05 01:25:11 +03:00
if (mainBundle != nil)
2015-02-04 09:24:40 +03:00
{
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
2017-11-05 01:25:11 +03:00
if (resourcesURL != nil)
2015-02-04 09:24:40 +03:00
{
char path[PATH_MAX];
2017-11-05 01:25:11 +03:00
if (CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8*)path, PATH_MAX) )
2015-02-04 09:24:40 +03:00
{
chdir(path);
}
2017-11-05 01:25:11 +03:00
2015-02-04 09:24:40 +03:00
CFRelease(resourcesURL);
}
}
MainThreadEntry* self = (MainThreadEntry*)_userData;
uint32_t result = main(self->m_argc, self->m_argv);
[NSApp terminate:nil];
return result;
}
};
2013-07-22 01:44:53 +04:00
struct Context
{
Context()
: m_scrollf(0.0f)
, m_mx(0)
, m_my(0)
, m_scroll(0)
, m_style(0)
2015-03-05 05:28:47 +03:00
, m_exit(false)
2020-03-29 17:58:37 +03:00
, m_mouseLock(NULL)
{
2014-09-29 00:36:23 +04:00
s_translateKey[27] = Key::Esc;
2017-11-17 04:51:34 +03:00
s_translateKey[uint8_t('\r')] = Key::Return;
2015-05-30 21:23:46 +03:00
s_translateKey[uint8_t('\t')] = Key::Tab;
2014-09-29 00:36:23 +04:00
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;
2015-05-30 21:23:46 +03:00
s_translateKey[uint8_t('~')] =
2015-05-30 23:11:18 +03:00
s_translateKey[uint8_t('`')] = Key::Tilde;
2015-05-30 21:23:46 +03:00
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;
2014-09-29 00:36:23 +04:00
for (char ch = 'a'; ch <= 'z'; ++ch)
{
2015-03-05 05:28:47 +03:00
s_translateKey[uint8_t(ch)] =
2014-09-29 00:36:23 +04:00
s_translateKey[uint8_t(ch - ' ')] = Key::KeyA + (ch - 'a');
}
for(int ii=0; ii<ENTRY_CONFIG_MAX_WINDOWS; ++ii)
{
m_window[ii] = NULL;
}
}
2013-07-22 01:44:53 +04:00
NSEvent* waitEvent()
2013-07-22 08:53:20 +04:00
{
return [NSApp
2018-02-21 00:20:45 +03:00
nextEventMatchingMask:NSEventMaskAny
2013-07-22 01:44:53 +04:00
untilDate:[NSDate distantFuture] // wait for event
inMode:NSDefaultRunLoopMode
2013-07-22 08:53:20 +04:00
dequeue:YES
];
}
2013-07-22 01:44:53 +04:00
NSEvent* peekEvent()
2013-07-22 08:53:20 +04:00
{
return [NSApp
2018-02-21 00:20:45 +03:00
nextEventMatchingMask:NSEventMaskAny
2013-07-22 01:44:53 +04:00
untilDate:[NSDate distantPast] // do not wait for event
inMode:NSDefaultRunLoopMode
2013-07-22 08:53:20 +04:00
dequeue:YES
];
}
2013-07-22 01:44:53 +04:00
void getMousePos(NSWindow *window, int* outX, int* outY)
{
//WindowHandle handle = { 0 };
//NSWindow* window = m_window[handle.idx];
2018-02-21 00:20:45 +03:00
NSRect originalFrame = [window frame];
NSPoint location = [window mouseLocationOutsideOfEventStream];
NSRect adjustFrame = [window contentRectForFrameRect: originalFrame];
2018-02-21 00:20:45 +03:00
int32_t x = location.x;
int32_t y = int32_t(adjustFrame.size.height) - int32_t(location.y);
2018-02-21 00:20:45 +03:00
// clamp within the range of the window
*outX = bx::clamp(x, 0, int32_t(adjustFrame.size.width) );
*outY = bx::clamp(y, 0, int32_t(adjustFrame.size.height) );
}
2020-03-29 17:58:37 +03:00
void setMousePos(NSWindow* _window, int _x, int _y)
{
NSRect originalFrame = [_window frame];
NSRect adjustFrame = [_window contentRectForFrameRect: originalFrame];
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
adjustFrame.origin.y = NSMaxY(NSScreen.screens[0].frame) - NSMaxY(adjustFrame);
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
CGWarpMouseCursorPosition(CGPointMake(_x + adjustFrame.origin.x, _y + adjustFrame.origin.y));
CGAssociateMouseAndMouseCursorPosition(YES);
}
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
void setMouseLock(NSWindow* _window, bool _lock)
{
NSWindow* newMouseLock = _lock ? _window : NULL;
if ( m_mouseLock != newMouseLock )
{
if ( _lock )
{
NSRect originalFrame = [_window frame];
NSRect adjustFrame = [_window contentRectForFrameRect: originalFrame];
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
m_cmx = (int)adjustFrame.size.width / 2;
m_cmy = (int)adjustFrame.size.height / 2;
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
setMousePos(_window, m_cmx, m_cmy);
[NSCursor hide];
}
else
{
[NSCursor unhide];
}
m_mouseLock = newMouseLock;
}
}
uint8_t translateModifiers(int flags)
{
2018-02-21 00:20:45 +03:00
return 0
2020-11-30 05:50:10 +03:00
| ( (0 != (flags & NX_DEVICELSHIFTKEYMASK) ) ? Modifier::LeftShift : 0)
| ( (0 != (flags & NX_DEVICERSHIFTKEYMASK) ) ? Modifier::RightShift : 0)
| ( (0 != (flags & NX_DEVICELALTKEYMASK) ) ? Modifier::LeftAlt : 0)
| ( (0 != (flags & NX_DEVICERALTKEYMASK) ) ? Modifier::RightAlt : 0)
| ( (0 != (flags & NX_DEVICELCTLKEYMASK) ) ? Modifier::LeftCtrl : 0)
| ( (0 != (flags & NX_DEVICERCTLKEYMASK) ) ? Modifier::RightCtrl : 0)
| ( (0 != (flags & NX_DEVICELCMDKEYMASK) ) ? Modifier::LeftMeta : 0)
| ( (0 != (flags & NX_DEVICERCMDKEYMASK) ) ? Modifier::RightMeta : 0)
2018-02-21 00:20:45 +03:00
;
}
2015-03-06 02:17:15 +03:00
Key::Enum handleKeyEvent(NSEvent* event, uint8_t* specialKeys, uint8_t* _pressedChar)
{
NSString* key = [event charactersIgnoringModifiers];
unichar keyChar = 0;
if ([key length] == 0)
2014-09-29 00:36:23 +04:00
{
return Key::None;
2014-09-29 00:36:23 +04:00
}
keyChar = [key characterAtIndex:0];
2015-03-06 02:17:15 +03:00
*_pressedChar = (uint8_t)keyChar;
int keyCode = keyChar;
*specialKeys = translateModifiers(int([event modifierFlags]));
// if this is a unhandled key just return None
2014-09-29 00:36:23 +04:00
if (keyCode < 256)
{
return (Key::Enum)s_translateKey[keyCode];
}
2014-09-29 00:36:23 +04:00
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;
}
2014-09-29 00:36:23 +04:00
return Key::None;
}
bool dispatchEvent(NSEvent* event)
2013-07-22 08:53:20 +04:00
{
if (event)
{
NSEventType eventType = [event type];
NSWindow *window = [event window];
WindowHandle handle = {UINT16_MAX};
if (nil != window)
{
handle = findHandle(window);
}
if (!isValid(handle))
{
[NSApp sendEvent:event];
[NSApp updateWindows];
return true;
}
switch (eventType)
{
2018-02-21 00:20:45 +03:00
case NSEventTypeMouseMoved:
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
getMousePos(window, &m_mx, &m_my);
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
if (window == m_mouseLock)
{
m_mx -= m_cmx;
m_my -= m_cmy;
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
setMousePos(window, m_cmx, m_cmy);
}
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll);
2017-07-16 01:37:40 +03:00
break;
2018-02-21 00:20:45 +03:00
case NSEventTypeLeftMouseDown:
{
// Command + Left Mouse Button acts as middle! This just a temporary solution!
2015-09-06 18:47:06 +03:00
// This is because the average OSX user doesn't have middle mouse click.
2018-02-21 00:20:45 +03:00
MouseButton::Enum mb = ([event modifierFlags] & NSEventModifierFlagCommand)
? MouseButton::Middle
: MouseButton::Left
;
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, mb, true);
}
2017-07-16 01:37:40 +03:00
break;
2018-02-21 00:20:45 +03:00
case NSEventTypeLeftMouseUp:
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, MouseButton::Left, false);
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, MouseButton::Middle, false);
2017-07-16 01:37:40 +03:00
break;
2018-02-21 00:20:45 +03:00
case NSEventTypeRightMouseDown:
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, MouseButton::Right, true);
2017-07-16 01:37:40 +03:00
break;
2018-02-21 00:20:45 +03:00
case NSEventTypeRightMouseUp:
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, MouseButton::Right, false);
2017-07-16 01:37:40 +03:00
break;
2015-03-05 05:28:47 +03:00
2018-02-21 00:20:45 +03:00
case NSEventTypeOtherMouseDown:
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, MouseButton::Middle, true);
2017-07-16 01:37:40 +03:00
break;
2015-03-05 05:28:47 +03:00
2018-02-21 00:20:45 +03:00
case NSEventTypeOtherMouseUp:
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, MouseButton::Middle, false);
2017-07-16 01:37:40 +03:00
break;
2015-03-05 05:28:47 +03:00
2018-02-21 00:20:45 +03:00
case NSEventTypeScrollWheel:
2017-07-16 01:37:40 +03:00
m_scrollf += [event deltaY];
2017-07-16 01:37:40 +03:00
m_scroll = (int32_t)m_scrollf;
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll);
2017-07-16 01:37:40 +03:00
break;
2018-02-21 00:20:45 +03:00
case NSEventTypeKeyDown:
{
uint8_t modifiers = 0;
2015-03-06 02:17:15 +03:00
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
{
2015-03-08 03:17:49 +03:00
enum { ShiftMask = Modifier::LeftShift|Modifier::RightShift };
m_eventQueue.postCharEvent(handle, 1, pressedChar);
m_eventQueue.postKeyEvent(handle, key, modifiers, true);
2015-03-19 19:31:46 +03:00
return false;
}
}
}
2017-07-16 01:37:40 +03:00
break;
2018-02-21 00:20:45 +03:00
case NSEventTypeKeyUp:
{
uint8_t modifiers = 0;
2015-03-06 02:17:15 +03:00
uint8_t pressedChar[4];
Key::Enum key = handleKeyEvent(event, &modifiers, &pressedChar[0]);
BX_UNUSED(pressedChar);
if (key != Key::None)
{
m_eventQueue.postKeyEvent(handle, key, modifiers, false);
return false;
}
}
2017-07-16 01:37:40 +03:00
break;
default:
break;
}
2014-09-29 00:36:23 +04:00
[NSApp sendEvent:event];
[NSApp updateWindows];
return true;
}
2013-07-22 08:53:20 +04:00
return false;
}
2013-07-22 01:44:53 +04:00
void windowDidResize(NSWindow *window)
2014-10-02 07:25:56 +04:00
{
WindowHandle handle = findHandle(window);
NSRect originalFrame = [window frame];
2015-03-08 05:03:55 +03:00
NSRect rect = [window contentRectForFrameRect: originalFrame];
2014-10-02 07:25:56 +04:00
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(handle, m_mx, m_my, m_scroll, MouseButton::Left, false);
m_eventQueue.postMouseEvent(handle, m_mx, m_my, m_scroll, MouseButton::Right, false);
2014-10-02 07:25:56 +04:00
}
void windowDidBecomeKey(NSWindow *window)
{
WindowHandle handle = findHandle(window);
m_eventQueue.postSuspendEvent(handle, Suspend::WillResume);
m_eventQueue.postSuspendEvent(handle, Suspend::DidResume);
}
void windowDidResignKey(NSWindow *window)
{
WindowHandle handle = findHandle(window);
m_eventQueue.postSuspendEvent(handle, Suspend::WillSuspend);
m_eventQueue.postSuspendEvent(handle, Suspend::DidSuspend);
}
2017-06-30 08:30:35 +03:00
int32_t run(int _argc, const char* const* _argv)
{
2013-07-22 01:44:53 +04:00
[NSApplication sharedApplication];
2013-07-22 08:53:20 +04:00
id dg = [AppDelegate sharedDelegate];
[NSApp setDelegate:dg];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
[NSApp finishLaunching];
2013-07-22 08:53:20 +04:00
[[NSNotificationCenter defaultCenter]
2013-07-22 01:44:53 +04:00
postNotificationName:NSApplicationWillFinishLaunchingNotification
object:NSApp];
2013-07-22 08:53:20 +04:00
[[NSNotificationCenter defaultCenter]
2013-07-22 01:44:53 +04:00
postNotificationName:NSApplicationDidFinishLaunchingNotification
object:NSApp];
id quitMenuItem = [NSMenuItem new];
[quitMenuItem
initWithTitle:@"Quit"
action:@selector(terminate:)
keyEquivalent:@"q"];
2013-07-22 08:53:20 +04:00
id appMenu = [NSMenu new];
[appMenu addItem:quitMenuItem];
2013-07-22 08:53:20 +04:00
id appMenuItem = [NSMenuItem new];
[appMenuItem setSubmenu:appMenu];
2013-07-22 08:53:20 +04:00
id menubar = [[NSMenu new] autorelease];
[menubar addItem:appMenuItem];
[NSApp setMainMenu:menubar];
2013-07-22 01:44:53 +04:00
m_style = 0
2018-02-26 18:55:43 +03:00
| NSWindowStyleMaskTitled
2018-02-21 00:20:45 +03:00
| NSWindowStyleMaskResizable
| NSWindowStyleMaskClosable
| NSWindowStyleMaskMiniaturizable
;
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;
2013-07-22 01:44:53 +04:00
NSString* appName = [[NSProcessInfo processInfo] processName];
createWindow(centerX, centerY, ENTRY_DEFAULT_WIDTH, ENTRY_DEFAULT_HEIGHT, ENTRY_WINDOW_FLAG_NONE, [appName UTF8String]);
2013-07-22 01:44:53 +04:00
m_windowFrame = [m_window[0] frame];
MainThreadEntry mte;
mte.m_argc = _argc;
mte.m_argv = _argv;
2013-07-22 01:44:53 +04:00
bx::Thread thread;
thread.init(mte.threadFunc, &mte);
2015-11-02 07:11:31 +03:00
WindowHandle handle = { 0 };
NSRect contentRect = [m_window[0] contentRectForFrameRect: m_windowFrame];
uint32_t width = uint32_t(contentRect.size.width);
uint32_t height = uint32_t(contentRect.size.height);
m_eventQueue.postSizeEvent(handle, width, height);
2015-11-02 07:11:31 +03:00
2013-07-22 08:53:20 +04:00
while (!(m_exit = [dg applicationHasTerminated]) )
{
bgfx::renderFrame();
2019-01-10 22:25:06 +03:00
@autoreleasepool
{
2019-01-10 22:25:06 +03:00
while (dispatchEvent(peekEvent() ) )
{
}
}
}
m_eventQueue.postExitEvent();
2013-07-22 01:44:53 +04:00
2013-12-07 22:19:54 +04:00
while (bgfx::RenderFrame::NoContext != bgfx::renderFrame() ) {};
thread.shutdown();
2013-07-22 01:44:53 +04:00
return 0;
}
2013-07-22 01:44:53 +04:00
WindowHandle findHandle(NSWindow *_window)
{
bx::MutexScope scope(m_lock);
for (uint16_t ii = 0, num = m_windowAlloc.getNumHandles(); ii < num; ++ii)
{
uint16_t idx = m_windowAlloc.getHandleAt(ii);
if (_window == m_window[idx])
{
WindowHandle handle = { idx };
return handle;
}
}
2019-04-13 17:51:25 +03:00
WindowHandle invalid = { UINT16_MAX };
return invalid;
}
EventQueue m_eventQueue;
bx::Mutex m_lock;
2013-07-22 01:44:53 +04:00
2014-10-02 07:25:56 +04:00
bx::HandleAllocT<ENTRY_CONFIG_MAX_WINDOWS> m_windowAlloc;
NSWindow* m_window[ENTRY_CONFIG_MAX_WINDOWS];
NSRect m_windowFrame;
2014-10-02 07:25:56 +04:00
float m_scrollf;
int32_t m_mx;
int32_t m_my;
2015-03-05 05:28:47 +03:00
int32_t m_scroll;
int32_t m_style;
bool m_exit;
2020-11-11 04:14:54 +03:00
2020-03-29 17:58:37 +03:00
NSWindow* m_mouseLock;
int32_t m_cmx;
int32_t m_cmy;
};
2013-07-22 01:44:53 +04:00
static Context s_ctx;
2013-07-22 01:44:53 +04:00
const Event* poll()
{
return s_ctx.m_eventQueue.poll();
}
2014-09-23 06:34:10 +04:00
const Event* poll(WindowHandle _handle)
{
return s_ctx.m_eventQueue.poll(_handle);
}
void release(const Event* _event)
{
s_ctx.m_eventQueue.release(_event);
}
2014-09-23 06:34:10 +04:00
WindowHandle createWindow(int32_t _x, int32_t _y, uint32_t _width, uint32_t _height, uint32_t _flags, const char* _title)
{
BX_UNUSED(_flags);
2019-04-13 17:51:25 +03:00
bx::MutexScope scope(s_ctx.m_lock);
WindowHandle handle = { s_ctx.m_windowAlloc.alloc() };
if (UINT16_MAX != handle.idx)
{
void (^createWindowBlock)(void) = ^(void) {
NSRect rect = NSMakeRect(_x, _y, _width, _height);
2019-04-27 05:33:32 +03:00
NSWindow* window = [
[NSWindow alloc]
initWithContentRect:rect
styleMask:s_ctx.m_style
backing:NSBackingStoreBuffered defer:NO
];
NSString* appName = [NSString stringWithUTF8String:_title];
[window setTitle:appName];
[window makeKeyAndOrderFront:window];
[window setAcceptsMouseMovedEvents:YES];
[window setBackgroundColor:[NSColor blackColor]];
[[Window sharedDelegate] windowCreated:window];
2019-04-13 17:51:25 +03:00
s_ctx.m_window[handle.idx] = window;
2019-04-13 17:51:25 +03:00
s_ctx.m_eventQueue.postSizeEvent(handle, _width, _height);
s_ctx.m_eventQueue.postWindowEvent(handle, window);
};
if ([NSThread isMainThread])
{
createWindowBlock();
}
else
{
dispatch_async(dispatch_get_main_queue(), createWindowBlock);
}
}
2014-09-23 06:34:10 +04:00
return handle;
}
void destroyWindow(WindowHandle _handle, bool _closeWindow)
2014-09-23 06:34:10 +04:00
{
if (isValid(_handle))
{
2019-04-27 05:33:32 +03:00
dispatch_async(dispatch_get_main_queue()
, ^(void){
NSWindow *window = s_ctx.m_window[_handle.idx];
if ( NULL != window)
{
s_ctx.m_eventQueue.postWindowEvent(_handle);
s_ctx.m_window[_handle.idx] = NULL;
if ( _closeWindow )
{
[window close];
}
if (0 == _handle.idx)
{
[NSApp terminate:nil];
}
}
});
bx::MutexScope scope(s_ctx.m_lock);
s_ctx.m_windowAlloc.free(_handle.idx);
}
2014-09-23 06:34:10 +04:00
}
2019-04-13 17:51:25 +03:00
void destroyWindow(WindowHandle _handle)
{
destroyWindow(_handle, true);
}
2014-09-23 06:34:10 +04:00
void setWindowPos(WindowHandle _handle, int32_t _x, int32_t _y)
{
dispatch_async(dispatch_get_main_queue()
2019-04-27 05:33:32 +03:00
, ^{
NSWindow* window = s_ctx.m_window[_handle.idx];
NSScreen* screen = [window screen];
2019-04-13 17:51:25 +03:00
2019-04-27 05:33:32 +03:00
NSRect screenRect = [screen frame];
CGFloat menuBarHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
2019-04-13 17:51:25 +03:00
2019-04-27 05:33:32 +03:00
NSPoint position = { float(_x), screenRect.size.height - menuBarHeight - float(_y) };
2019-04-13 17:51:25 +03:00
2019-04-27 05:33:32 +03:00
[window setFrameTopLeftPoint: position];
});
2014-09-23 06:34:10 +04:00
}
2014-09-19 21:33:13 +04:00
void setWindowSize(WindowHandle _handle, uint32_t _width, uint32_t _height)
{
NSSize size = { float(_width), float(_height) };
dispatch_async(dispatch_get_main_queue()
2019-04-27 05:33:32 +03:00
, ^{
[s_ctx.m_window[_handle.idx] setContentSize: size];
});
}
2014-09-19 21:33:13 +04:00
void setWindowTitle(WindowHandle _handle, const char* _title)
2014-08-05 23:57:52 +04:00
{
NSString* title = [[NSString alloc] initWithCString:_title encoding:1];
dispatch_async(dispatch_get_main_queue()
2019-04-27 05:33:32 +03:00
, ^{
[s_ctx.m_window[_handle.idx] setTitle: title];
[title release];
});
2014-08-05 23:57:52 +04:00
}
2018-01-03 06:15:04 +03:00
void setWindowFlags(WindowHandle _handle, uint32_t _flags, bool _enabled)
{
2018-01-03 06:15:04 +03:00
BX_UNUSED(_handle, _flags, _enabled);
}
void toggleFullscreen(WindowHandle _handle)
{
dispatch_async(dispatch_get_main_queue()
2019-04-27 05:33:32 +03:00
, ^{
NSWindow* window = s_ctx.m_window[_handle.idx];
[window toggleFullScreen:nil];
2019-04-27 05:33:32 +03:00
});
}
2014-09-19 21:33:13 +04:00
void setMouseLock(WindowHandle _handle, bool _lock)
2013-01-19 12:22:25 +04:00
{
2020-03-29 17:58:37 +03:00
dispatch_async(dispatch_get_main_queue()
, ^{
NSWindow* window = s_ctx.m_window[_handle.idx];
s_ctx.setMouseLock(window, _lock);
});
2013-01-19 12:22:25 +04:00
}
void* getNativeWindowHandle(WindowHandle _handle)
{
return s_ctx.m_window[_handle.idx];
}
void* getNativeDisplayHandle()
{
return NULL;
}
bgfx::NativeWindowHandleType::Enum getNativeWindowHandleType(WindowHandle _handle)
{
2023-08-17 20:28:22 +03:00
BX_UNUSED(_handle);
return bgfx::NativeWindowHandleType::Default;
}
} // namespace entry
2014-10-02 07:25:56 +04:00
@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;
}
return self;
}
- (void)windowCreated:(NSWindow*)window
{
assert(window);
[window setDelegate:self];
}
- (void)windowWillClose:(NSNotification*)notification
{
BX_UNUSED(notification);
NSWindow *window = [notification object];
[window setDelegate:nil];
2019-04-13 17:51:25 +03:00
destroyWindow(entry::s_ctx.findHandle(window), false);
2014-10-02 07:25:56 +04:00
}
- (BOOL)windowShouldClose:(NSWindow*)window
{
assert(window);
2019-04-13 17:51:25 +03:00
BX_UNUSED(window);
2014-10-02 07:25:56 +04:00
return true;
}
- (void)windowDidResize:(NSNotification*)notification
{
NSWindow *window = [notification object];
2014-10-02 07:25:56 +04:00
using namespace entry;
s_ctx.windowDidResize(window);
2014-10-02 07:25:56 +04:00
}
- (void)windowDidBecomeKey:(NSNotification*)notification
{
NSWindow *window = [notification object];
using namespace entry;
s_ctx.windowDidBecomeKey(window);
}
- (void)windowDidResignKey:(NSNotification*)notification
{
NSWindow *window = [notification object];
using namespace entry;
s_ctx.windowDidResignKey(window);
}
2014-10-02 07:25:56 +04:00
@end
2017-06-30 08:30:35 +03:00
int main(int _argc, const char* const* _argv)
{
using namespace entry;
2013-07-22 08:53:20 +04:00
return s_ctx.run(_argc, _argv);
}
#endif // BX_PLATFORM_OSX