More TextInput implementation

This commit is contained in:
Jack Andersen 2015-12-26 18:20:07 -10:00
parent fb1282c3e4
commit 9f9ff269fe
5 changed files with 160 additions and 110 deletions

View File

@ -46,6 +46,10 @@ elseif(APPLE)
lib/inputdev/HIDListenerIOKit.cpp lib/inputdev/HIDListenerIOKit.cpp
lib/inputdev/HIDDeviceIOKit.cpp lib/inputdev/HIDDeviceIOKit.cpp
lib/graphicsdev/Metal.mm) lib/graphicsdev/Metal.mm)
set_source_files_properties(lib/mac/ApplicationCocoa.mm
lib/mac/WindowCocoa.mm
lib/graphicsdev/Metal.mm
PROPERTIES COMPILE_FLAGS -fobjc-arc)
list(APPEND PLAT_HDRS list(APPEND PLAT_HDRS
include/boo/graphicsdev/Metal.hpp) include/boo/graphicsdev/Metal.hpp)

View File

@ -5,6 +5,10 @@
#include "boo/IGraphicsContext.hpp" #include "boo/IGraphicsContext.hpp"
#include <vector> #include <vector>
#if !__has_feature(objc_arc)
#error ARC Required
#endif
#define MAX_UNIFORM_COUNT 8 #define MAX_UNIFORM_COUNT 8
#define MAX_TEXTURE_COUNT 8 #define MAX_TEXTURE_COUNT 8
@ -94,9 +98,9 @@ class MetalTextureS : public ITextureS
NSPtr<MTLTextureDescriptor*> desc; NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
width:width height:height width:width height:height
mipmapped:(mips>1)?YES:NO] retain]; mipmapped:(mips>1)?YES:NO];
} }
desc.get().usage = MTLTextureUsageShaderRead; desc.get().usage = MTLTextureUsageShaderRead;
desc.get().mipmapLevelCount = mips; desc.get().mipmapLevelCount = mips;
@ -138,9 +142,9 @@ class MetalTextureSA : public ITextureSA
NSPtr<MTLTextureDescriptor*> desc; NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
width:width height:height width:width height:height
mipmapped:NO] retain]; mipmapped:NO];
} }
desc.get().textureType = MTLTextureType2DArray; desc.get().textureType = MTLTextureType2DArray;
desc.get().arrayLength = layers; desc.get().arrayLength = layers;
@ -198,9 +202,9 @@ class MetalTextureD : public ITextureD
NSPtr<MTLTextureDescriptor*> desc; NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
width:width height:height width:width height:height
mipmapped:NO] retain]; mipmapped:NO];
} }
desc.get().usage = MTLTextureUsageShaderRead; desc.get().usage = MTLTextureUsageShaderRead;
m_texs[0] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()]; m_texs[0] = [ctx->m_dev.get() newTextureWithDescriptor:desc.get()];
@ -229,10 +233,10 @@ class MetalTextureR : public ITextureR
NSPtr<MTLTextureDescriptor*> desc; NSPtr<MTLTextureDescriptor*> desc;
@autoreleasepool @autoreleasepool
{ {
desc = [[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:width height:height width:width height:height
mipmapped:NO] retain]; mipmapped:NO];
m_passDesc = [[MTLRenderPassDescriptor renderPassDescriptor] retain]; m_passDesc = [MTLRenderPassDescriptor renderPassDescriptor];
} }
desc.get().usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead; desc.get().usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
desc.get().storageMode = MTLStorageModePrivate; desc.get().storageMode = MTLStorageModePrivate;
@ -555,7 +559,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
{ {
@autoreleasepool @autoreleasepool
{ {
m_cmdBuf = [[ctx->m_q.get() commandBuffer] retain]; m_cmdBuf = [ctx->m_q.get() commandBuffer];
} }
} }
@ -586,7 +590,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
[m_enc.get() endEncoding]; [m_enc.get() endEncoding];
@autoreleasepool @autoreleasepool
{ {
m_enc = [[m_cmdBuf.get() renderCommandEncoderWithDescriptor:ctarget->m_passDesc.get()] retain]; m_enc = [m_cmdBuf.get() renderCommandEncoderWithDescriptor:ctarget->m_passDesc.get()];
} }
m_boundTarget = ctarget; m_boundTarget = ctarget;
} }
@ -738,7 +742,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
/* Abandon if in progress (renderer too slow) */ /* Abandon if in progress (renderer too slow) */
if (m_inProgress) if (m_inProgress)
{ {
m_cmdBuf = [[m_ctx->m_q.get() commandBuffer] retain]; m_cmdBuf = [m_ctx->m_q.get() commandBuffer];
return; return;
} }
@ -748,7 +752,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
for (const auto& resize : m_texResizes) for (const auto& resize : m_texResizes)
resize.first->resize(m_ctx, resize.second.first, resize.second.second); resize.first->resize(m_ctx, resize.second.first, resize.second.second);
m_texResizes.clear(); m_texResizes.clear();
m_cmdBuf = [[m_ctx->m_q.get() commandBuffer] retain]; m_cmdBuf = [m_ctx->m_q.get() commandBuffer];
return; return;
} }
@ -758,7 +762,7 @@ struct MetalCommandQueue : IGraphicsCommandQueue
[m_cmdBuf.get() addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}]; [m_cmdBuf.get() addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}];
m_inProgress = true; m_inProgress = true;
[m_cmdBuf.get() commit]; [m_cmdBuf.get() commit];
m_cmdBuf = [[m_ctx->m_q.get() commandBuffer] retain]; m_cmdBuf = [m_ctx->m_q.get() commandBuffer];
} }
} }
}; };

View File

@ -7,6 +7,10 @@
#include <LogVisor/LogVisor.hpp> #include <LogVisor/LogVisor.hpp>
#if !__has_feature(objc_arc)
#error ARC Required
#endif
namespace boo {class ApplicationCocoa;} namespace boo {class ApplicationCocoa;}
@interface AppDelegate : NSObject <NSApplicationDelegate> @interface AppDelegate : NSObject <NSApplicationDelegate>
{ {
@ -26,8 +30,8 @@ IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
class ApplicationCocoa : public IApplication class ApplicationCocoa : public IApplication
{ {
public: public:
NSApplication* m_app = nullptr;
IApplicationCallback& m_callback; IApplicationCallback& m_callback;
AppDelegate* m_appDelegate;
private: private:
const SystemString m_uniqueName; const SystemString m_uniqueName;
const SystemString m_friendlyName; const SystemString m_friendlyName;
@ -37,13 +41,13 @@ private:
NSPanel* aboutPanel; NSPanel* aboutPanel;
/* All windows */ /* All windows */
std::unordered_map<NSWindow*, IWindow*> m_windows; std::unordered_map<uintptr_t, IWindow*> m_windows;
MetalContext m_metalCtx; MetalContext m_metalCtx;
void _deletedWindow(IWindow* window) void _deletedWindow(IWindow* window)
{ {
m_windows.erase((NSWindow*)window->getPlatformHandle()); m_windows.erase(window->getPlatformHandle());
} }
public: public:
@ -58,17 +62,16 @@ public:
m_pname(pname), m_pname(pname),
m_args(args) m_args(args)
{ {
m_app = [NSApplication sharedApplication]; [[NSApplication sharedApplication] setActivationPolicy:NSApplicationActivationPolicyRegular];
[m_app setActivationPolicy:NSApplicationActivationPolicyRegular];
/* Delegate (OS X callbacks) */ /* Delegate (OS X callbacks) */
AppDelegate* appDelegate = [[AppDelegate alloc] initWithApp:this]; m_appDelegate = [[AppDelegate alloc] initWithApp:this];
[m_app setDelegate:appDelegate]; [[NSApplication sharedApplication] setDelegate:m_appDelegate];
/* App menu */ /* App menu */
NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"]; NSMenu* appMenu = [[NSMenu alloc] initWithTitle:@"main"];
NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease]]; NSMenu* rwkMenu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]];
[rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease] [rwkMenu addItemWithTitle:[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()]
action:@selector(aboutApp:) action:@selector(aboutApp:)
keyEquivalent:@""]; keyEquivalent:@""];
NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen" NSMenuItem* fsItem = [rwkMenu addItemWithTitle:@"Toggle Full Screen"
@ -76,11 +79,11 @@ public:
keyEquivalent:@"f"]; keyEquivalent:@"f"];
[fsItem setKeyEquivalentModifierMask:NSCommandKeyMask]; [fsItem setKeyEquivalentModifierMask:NSCommandKeyMask];
[rwkMenu addItem:[NSMenuItem separatorItem]]; [rwkMenu addItem:[NSMenuItem separatorItem]];
NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()] autorelease] NSMenuItem* quit_item = [rwkMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %s", m_friendlyName.c_str()]
action:@selector(quitApp:) action:@selector(quitApp:)
keyEquivalent:@"q"]; keyEquivalent:@"q"];
[quit_item setKeyEquivalentModifierMask:NSCommandKeyMask]; [quit_item setKeyEquivalentModifierMask:NSCommandKeyMask];
[[appMenu addItemWithTitle:[[NSString stringWithUTF8String:m_friendlyName.c_str()] autorelease] [[appMenu addItemWithTitle:[NSString stringWithUTF8String:m_friendlyName.c_str()]
action:nil keyEquivalent:@""] setSubmenu:rwkMenu]; action:nil keyEquivalent:@""] setSubmenu:rwkMenu];
[[NSApplication sharedApplication] setMainMenu:appMenu]; [[NSApplication sharedApplication] setMainMenu:appMenu];
@ -89,13 +92,13 @@ public:
aboutPanel = [[NSPanel alloc] initWithContentRect:aboutCr aboutPanel = [[NSPanel alloc] initWithContentRect:aboutCr
styleMask:NSUtilityWindowMask|NSTitledWindowMask|NSClosableWindowMask styleMask:NSUtilityWindowMask|NSTitledWindowMask|NSClosableWindowMask
backing:NSBackingStoreBuffered defer:YES]; backing:NSBackingStoreBuffered defer:YES];
[aboutPanel setTitle:[[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()] autorelease]]; [aboutPanel setTitle:[NSString stringWithFormat:@"About %s", m_friendlyName.c_str()]];
NSText* aboutText = [[NSText alloc] initWithFrame:aboutCr]; NSText* aboutText = [[NSText alloc] initWithFrame:aboutCr];
[aboutText setEditable:NO]; [aboutText setEditable:NO];
[aboutText setAlignment:NSCenterTextAlignment]; [aboutText setAlignment:NSCenterTextAlignment];
[aboutText setString:@"\nBoo Authors\n\nJackoalan\nAntidote\n"]; [aboutText setString:@"\nBoo Authors\n\nJackoalan\nAntidote\n"];
[aboutPanel setContentView:aboutText]; [aboutPanel setContentView:aboutText];
appDelegate->aboutPanel = aboutPanel; m_appDelegate->aboutPanel = aboutPanel;
/* Determine which graphics API to use */ /* Determine which graphics API to use */
#if BOO_HAS_METAL #if BOO_HAS_METAL
@ -166,7 +169,7 @@ public:
IWindow* newWindow(const std::string& title) IWindow* newWindow(const std::string& title)
{ {
IWindow* newWindow = _WindowCocoaNew(title, m_lastGLCtx, &m_metalCtx); IWindow* newWindow = _WindowCocoaNew(title, m_lastGLCtx, &m_metalCtx);
m_windows[(NSWindow*)newWindow->getPlatformHandle()] = newWindow; m_windows[newWindow->getPlatformHandle()] = newWindow;
return newWindow; return newWindow;
} }
@ -197,7 +200,7 @@ int ApplicationRun(IApplication::EPlatformType platform,
return 1; return 1;
APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args); APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args);
} }
[static_cast<ApplicationCocoa*>(APP)->m_app run]; [[NSApplication sharedApplication] run];
return static_cast<ApplicationCocoa*>(APP)->m_clientReturn; return static_cast<ApplicationCocoa*>(APP)->m_clientReturn;
} }
} }

View File

@ -3,23 +3,39 @@
#if __APPLE__ #if __APPLE__
#include <Availability.h> #include <Availability.h>
#include <utility>
template <class T> template <class T>
class NSPtr class NSPtr
{ {
T m_ptr = 0; void* m_ptr = nullptr;
public: public:
NSPtr() = default; NSPtr() = default;
~NSPtr() {[m_ptr release];} ~NSPtr()
NSPtr(T&& recv) : m_ptr(recv) {} {
NSPtr& operator=(T&& recv) {[m_ptr release]; m_ptr = recv; return *this;} T ptr = (__bridge_transfer T)m_ptr;
(void)ptr;
}
NSPtr(T&& recv) {*this = std::move(recv);}
NSPtr& operator=(T&& recv)
{
T old = (__bridge_transfer T)m_ptr;
(void)old;
m_ptr = (__bridge_retained void*)recv;
return *this;
}
NSPtr(const NSPtr& other) = delete; NSPtr(const NSPtr& other) = delete;
NSPtr(NSPtr&& other) = default; NSPtr(NSPtr&& other) = default;
NSPtr& operator=(const NSPtr& other) = delete; NSPtr& operator=(const NSPtr& other) = delete;
NSPtr& operator=(NSPtr&& other) = default; NSPtr& operator=(NSPtr&& other) = default;
operator bool() const {return m_ptr != 0;} operator bool() const {return m_ptr != 0;}
T get() const {return m_ptr;} T get() const {return (__bridge T)m_ptr;}
void reset() {[m_ptr release]; m_ptr = 0;} void reset()
{
T old = (__bridge_transfer T)m_ptr;
(void)old;
m_ptr = nullptr;
}
}; };
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100

View File

@ -10,7 +10,11 @@
#include <LogVisor/LogVisor.hpp> #include <LogVisor/LogVisor.hpp>
namespace boo {class WindowCocoa;} #if !__has_feature(objc_arc)
#error ARC Required
#endif
namespace boo {class WindowCocoa; class GraphicsContextCocoa;}
@interface WindowCocoaInternal : NSWindow @interface WindowCocoaInternal : NSWindow
{ {
boo::WindowCocoa* booWindow; boo::WindowCocoa* booWindow;
@ -75,8 +79,20 @@ static const NSOpenGLPixelFormatAttribute* PF_TABLE[] =
PF_RGBAF32_Z24_ATTRS PF_RGBAF32_Z24_ATTRS
}; };
@interface BooCocoaResponder : NSResponder <NSTextInputClient>
{
@public
NSUInteger lastModifiers;
boo::GraphicsContextCocoa* booContext;
NSView* parentView;
NSTextInputContext* textContext;
}
- (id)initWithBooContext:(boo::GraphicsContextCocoa*)bctx View:(NSView*)view;
@end
namespace boo namespace boo
{ {
class GraphicsContextCocoa : public IGraphicsContext class GraphicsContextCocoa : public IGraphicsContext
{ {
protected: protected:
@ -102,6 +118,7 @@ protected:
return kCVReturnSuccess; return kCVReturnSuccess;
} }
public:
~GraphicsContextCocoa() ~GraphicsContextCocoa()
{ {
if (m_dispLink) if (m_dispLink)
@ -111,31 +128,21 @@ protected:
} }
} }
public:
IWindowCallback* m_callback = nullptr; IWindowCallback* m_callback = nullptr;
void waitForRetrace() void waitForRetrace()
{ {
std::unique_lock<std::mutex> lk(m_dlmt); std::unique_lock<std::mutex> lk(m_dlmt);
m_dlcv.wait(lk); m_dlcv.wait(lk);
} }
virtual BooCocoaResponder* responder() const=0;
}; };
class GraphicsContextCocoaGL; class GraphicsContextCocoaGL;
class GraphicsContextCocoaMetal; class GraphicsContextCocoaMetal;
} }
@interface BooCocoaResponder : NSResponder <NSTextInputClient>
{
@public
NSUInteger lastModifiers;
boo::GraphicsContextCocoa* booContext;
NSView* parentView;
NSTextInputContext* textContext;
}
- (id)initWithBooContext:(boo::GraphicsContextCocoa*)bctx View:(NSView*)view;
@end
@interface GraphicsContextCocoaGLInternal : NSOpenGLView @interface GraphicsContextCocoaGLInternal : NSOpenGLView
{ {
@public
BooCocoaResponder* resp; BooCocoaResponder* resp;
} }
- (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx; - (id)initWithBooContext:(boo::GraphicsContextCocoaGL*)bctx;
@ -143,6 +150,7 @@ class GraphicsContextCocoaMetal;
@interface GraphicsContextCocoaMetalInternal : NSView @interface GraphicsContextCocoaMetalInternal : NSView
{ {
@public
BooCocoaResponder* resp; BooCocoaResponder* resp;
boo::MetalContext* m_ctx; boo::MetalContext* m_ctx;
boo::IWindow* m_window; boo::IWindow* m_window;
@ -182,8 +190,6 @@ public:
{ {
delete m_dataFactory; delete m_dataFactory;
delete m_commandQueue; delete m_commandQueue;
[m_nsContext release];
[m_loadCtx release];
} }
void _setCallback(IWindowCallback* cb) void _setCallback(IWindowCallback* cb)
@ -213,7 +219,7 @@ public:
m_nsContext = [[GraphicsContextCocoaGLInternal alloc] initWithBooContext:this]; m_nsContext = [[GraphicsContextCocoaGLInternal alloc] initWithBooContext:this];
if (!m_nsContext) if (!m_nsContext)
Log.report(LogVisor::FatalError, "unable to make new NSOpenGLView"); Log.report(LogVisor::FatalError, "unable to make new NSOpenGLView");
[(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext]; [(__bridge NSWindow*)(void*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext];
CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink); CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink);
CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this);
CVDisplayLinkStart(m_dispLink); CVDisplayLinkStart(m_dispLink);
@ -245,7 +251,6 @@ public:
{ {
NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[int(m_pf)]]; NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[int(m_pf)]];
m_mainCtx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:[m_nsContext openGLContext]]; m_mainCtx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:[m_nsContext openGLContext]];
[nspf release];
if (!m_mainCtx) if (!m_mainCtx)
Log.report(LogVisor::FatalError, "unable to make main NSOpenGLContext"); Log.report(LogVisor::FatalError, "unable to make main NSOpenGLContext");
} }
@ -259,7 +264,6 @@ public:
{ {
NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[int(m_pf)]]; NSOpenGLPixelFormat* nspf = [[NSOpenGLPixelFormat alloc] initWithAttributes:PF_TABLE[int(m_pf)]];
m_loadCtx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:[m_nsContext openGLContext]]; m_loadCtx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:[m_nsContext openGLContext]];
[nspf release];
if (!m_loadCtx) if (!m_loadCtx)
Log.report(LogVisor::FatalError, "unable to make load NSOpenGLContext"); Log.report(LogVisor::FatalError, "unable to make load NSOpenGLContext");
} }
@ -272,6 +276,13 @@ public:
[[m_nsContext openGLContext] flushBuffer]; [[m_nsContext openGLContext] flushBuffer];
} }
BooCocoaResponder* responder() const
{
if (!m_nsContext)
return nullptr;
return m_nsContext->resp;
}
}; };
IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api, IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api,
@ -285,7 +296,6 @@ IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api,
if (!nspf) if (!nspf)
return NULL; return NULL;
NSOpenGLContext* nsctx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:nil]; NSOpenGLContext* nsctx = [[NSOpenGLContext alloc] initWithFormat:nspf shareContext:nil];
[nspf release];
if (!nsctx) if (!nsctx)
return NULL; return NULL;
[nsctx makeCurrentContext]; [nsctx makeCurrentContext];
@ -298,7 +308,6 @@ IGraphicsContext* _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI api,
minor = glVersion[2] - '0'; minor = glVersion[2] - '0';
} }
[NSOpenGLContext clearCurrentContext]; [NSOpenGLContext clearCurrentContext];
[nsctx release];
if (!glVersion) if (!glVersion)
return NULL; return NULL;
@ -335,7 +344,6 @@ public:
{ {
delete m_dataFactory; delete m_dataFactory;
delete m_commandQueue; delete m_commandQueue;
[m_nsContext release];
m_metalCtx->m_windows.erase(m_parentWindow); m_metalCtx->m_windows.erase(m_parentWindow);
} }
@ -368,7 +376,7 @@ public:
if (!m_nsContext) if (!m_nsContext)
Log.report(LogVisor::FatalError, "unable to make new NSView for Metal"); Log.report(LogVisor::FatalError, "unable to make new NSView for Metal");
w.m_metalLayer = (CAMetalLayer*)m_nsContext.layer; w.m_metalLayer = (CAMetalLayer*)m_nsContext.layer;
[(NSWindow*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext]; [(__bridge NSWindow*)(void*)m_parentWindow->getPlatformHandle() setContentView:m_nsContext];
CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink); CVDisplayLinkCreateWithActiveCGDisplays(&m_dispLink);
CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this); CVDisplayLinkSetOutputCallback(m_dispLink, (CVDisplayLinkOutputCallback)DLCallback, this);
CVDisplayLinkStart(m_dispLink); CVDisplayLinkStart(m_dispLink);
@ -407,6 +415,13 @@ public:
{ {
} }
BooCocoaResponder* responder() const
{
if (!m_nsContext)
return nullptr;
return m_nsContext->resp;
}
}; };
IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI api, IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI api,
@ -433,6 +448,7 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (BOOL)hasMarkedText - (BOOL)hasMarkedText
{ {
NSLog(@"hasMarkedText");
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
@ -444,6 +460,7 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (NSRange)markedRange - (NSRange)markedRange
{ {
NSLog(@"markedRange");
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
@ -458,6 +475,7 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (NSRange)selectedRange - (NSRange)selectedRange
{ {
NSLog(@"selectedRange");
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
@ -472,29 +490,28 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{ {
NSLog(@"setMarkedText %@ [%lu,%lu] [%lu,%lu]", aString,
selectedRange.location, selectedRange.length,
replacementRange.location, replacementRange.length);
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
if (textCb) if (textCb)
{ {
NSString* plainStr; NSString* plainStr = aString;
if ([aString isKindOfClass:[NSAttributedString class]]) if ([aString isKindOfClass:[NSAttributedString class]])
plainStr = ((NSAttributedString*)aString).string; plainStr = ((NSAttributedString*)aString).string;
else
{
plainStr = aString;
[plainStr retain];
}
textCb->setMarkedText([plainStr UTF8String], textCb->setMarkedText([plainStr UTF8String],
std::make_pair(selectedRange.location, selectedRange.length), std::make_pair(selectedRange.location, selectedRange.length),
std::make_pair(replacementRange.location, replacementRange.length)); std::make_pair(replacementRange.location==NSNotFound ? -1 : replacementRange.location,
[plainStr release]; replacementRange.length));
} }
} }
} }
- (void)unmarkText - (void)unmarkText
{ {
NSLog(@"unmarkText");
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
@ -505,11 +522,12 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (NSArray<NSString*>*)validAttributesForMarkedText - (NSArray<NSString*>*)validAttributesForMarkedText
{ {
return [NSArray array]; return @[];
} }
- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange - (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{ {
NSLog(@"attributedSubstringForProposedRange");
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
@ -523,7 +541,6 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
actualRange->length = actualRng.second; actualRange->length = actualRng.second;
NSString* nsStr = [NSString stringWithUTF8String:str.c_str()]; NSString* nsStr = [NSString stringWithUTF8String:str.c_str()];
NSAttributedString* ret = [[NSAttributedString alloc] initWithString:nsStr]; NSAttributedString* ret = [[NSAttributedString alloc] initWithString:nsStr];
[nsStr release];
return ret; return ret;
} }
} }
@ -532,28 +549,25 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
{ {
NSLog(@"insertText %@ [%lu,%lu]", aString, replacementRange.location, replacementRange.length);
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
if (textCb) if (textCb)
{ {
NSString* plainStr; NSString* plainStr = aString;
if ([aString isKindOfClass:[NSAttributedString class]]) if ([aString isKindOfClass:[NSAttributedString class]])
plainStr = ((NSAttributedString*)aString).string; plainStr = ((NSAttributedString*)aString).string;
else
{
plainStr = aString;
[plainStr retain];
}
textCb->insertText([plainStr UTF8String], textCb->insertText([plainStr UTF8String],
std::make_pair(replacementRange.location, replacementRange.length)); std::make_pair(replacementRange.location == NSNotFound ? -1 : replacementRange.location,
[plainStr release]; replacementRange.length));
} }
} }
} }
- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint - (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
{ {
NSLog(@"characterIndexForPoint");
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
@ -572,6 +586,7 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{ {
NSLog(@"firstRectForCharacterRange");
if (booContext->m_callback) if (booContext->m_callback)
{ {
boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback(); boo::ITextInputCallback* textCb = booContext->m_callback->getTextInputCallback();
@ -592,7 +607,7 @@ IGraphicsContext* _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI a
- (void)doCommandBySelector:(SEL)aSelector - (void)doCommandBySelector:(SEL)aSelector
{ {
NSLog(@"doCommandBySelector %@", NSStringFromSelector(aSelector));
} }
static inline boo::EModifierKey getMod(NSUInteger flags) static inline boo::EModifierKey getMod(NSUInteger flags)
@ -987,7 +1002,7 @@ static boo::ESpecialKey translateKeycode(short code)
else if ([chars length]) else if ([chars length])
booContext->m_callback->charKeyUp([chars characterAtIndex:0], booContext->m_callback->charKeyUp([chars characterAtIndex:0],
getMod(theEvent.modifierFlags)); getMod(theEvent.modifierFlags));
[textContext handleEvent:theEvent]; //[textContext handleEvent:theEvent];
} }
- (void)flagsChanged:(NSEvent*)theEvent - (void)flagsChanged:(NSEvent*)theEvent
@ -1034,12 +1049,6 @@ static boo::ESpecialKey translateKeycode(short code)
return YES; return YES;
} }
- (void)dealloc
{
[textContext release];
[super dealloc];
}
@end @end
@implementation GraphicsContextCocoaGLInternal @implementation GraphicsContextCocoaGLInternal
@ -1055,16 +1064,9 @@ static boo::ESpecialKey translateKeycode(short code)
[self setOpenGLContext:sharedCtx]; [self setOpenGLContext:sharedCtx];
[sharedCtx setView:self]; [sharedCtx setView:self];
} }
[nspf release];
return self; return self;
} }
- (void)dealloc
{
[resp release];
[super dealloc];
}
- (void)reshape - (void)reshape
{ {
boo::SWindowRect rect = {{int(self.frame.origin.x), int(self.frame.origin.y)}, boo::SWindowRect rect = {{int(self.frame.origin.x), int(self.frame.origin.y)},
@ -1103,12 +1105,6 @@ static boo::ESpecialKey translateKeycode(short code)
return self; return self;
} }
- (void)dealloc
{
[resp release];
[super dealloc];
}
- (CALayer*)makeBackingLayer - (CALayer*)makeBackingLayer
{ {
CAMetalLayer* layer = [CAMetalLayer new]; CAMetalLayer* layer = [CAMetalLayer new];
@ -1169,11 +1165,16 @@ static boo::ESpecialKey translateKeycode(short code)
namespace boo namespace boo
{ {
static NSString* ClipboardTypes[] =
{
0, NSPasteboardTypeString, NSPasteboardTypeString, NSPasteboardTypePNG
};
class WindowCocoa : public IWindow class WindowCocoa : public IWindow
{ {
WindowCocoaInternal* m_nsWindow; WindowCocoaInternal* m_nsWindow;
IGraphicsContext* m_gfxCtx; GraphicsContextCocoa* m_gfxCtx;
EMouseCursor m_cursor = EMouseCursor::None; EMouseCursor m_cursor = EMouseCursor::None;
public: public:
@ -1185,16 +1186,18 @@ public:
m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title]; m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title];
#if BOO_HAS_METAL #if BOO_HAS_METAL
if (metalCtx->m_dev) if (metalCtx->m_dev)
m_gfxCtx = _GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal, this, metalCtx); m_gfxCtx = static_cast<GraphicsContextCocoa*>(_GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal, this, metalCtx));
else else
#endif #endif
m_gfxCtx = _GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this, lastGLCtx); m_gfxCtx = static_cast<GraphicsContextCocoa*>(_GraphicsContextCocoaGLNew(IGraphicsContext::EGraphicsAPI::OpenGL3_3, this, lastGLCtx));
m_gfxCtx->initializeContext(); m_gfxCtx->initializeContext();
}); });
} }
void _clearWindow() void _clearWindow()
{ {
/* Caller consumes reference on its own */
(void)(__bridge_retained void*)m_nsWindow;
m_nsWindow = nullptr; m_nsWindow = nullptr;
} }
@ -1202,7 +1205,6 @@ public:
{ {
[m_nsWindow orderOut:nil]; [m_nsWindow orderOut:nil];
delete m_gfxCtx; delete m_gfxCtx;
[m_nsWindow release];
APP->_deletedWindow(this); APP->_deletedWindow(this);
} }
@ -1236,7 +1238,7 @@ public:
{ {
dispatch_sync(dispatch_get_main_queue(), dispatch_sync(dispatch_get_main_queue(),
^{ ^{
[m_nsWindow setTitle:[[NSString stringWithUTF8String:title.c_str()] autorelease]]; [m_nsWindow setTitle:[NSString stringWithUTF8String:title.c_str()]];
}); });
} }
@ -1337,17 +1339,38 @@ public:
void claimKeyboardFocus(const int coord[2]) void claimKeyboardFocus(const int coord[2])
{ {
BooCocoaResponder* resp = m_gfxCtx->responder();
if (resp)
{
dispatch_async(dispatch_get_main_queue(),
^{
if (coord)
[resp->textContext activate];
else
[resp->textContext deactivate];
});
}
} }
bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz) bool clipboardCopy(EClipboardType type, const uint8_t* data, size_t sz)
{ {
NSPasteboard* pb = [NSPasteboard generalPasteboard];
[pb clearContents];
NSData* d = [NSData dataWithBytes:data length:sz];
[pb setData:d forType:ClipboardTypes[int(type)]];
return true;
} }
std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz) std::unique_ptr<uint8_t[]> clipboardPaste(EClipboardType type, size_t& sz)
{ {
NSPasteboard* pb = [NSPasteboard generalPasteboard];
NSData* d = [pb dataForType:ClipboardTypes[int(type)]];
if (!d)
return std::unique_ptr<uint8_t[]>();
sz = [d length];
std::unique_ptr<uint8_t[]> ret(new uint8_t[sz]);
[d getBytes:ret.get() length:sz];
return ret;
} }
ETouchType getTouchType() const ETouchType getTouchType() const
@ -1437,7 +1460,7 @@ IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
NSResizableWindowMask NSResizableWindowMask
backing:NSBackingStoreBuffered backing:NSBackingStoreBuffered
defer:YES]; defer:YES];
self.title = [[NSString stringWithUTF8String:title.c_str()] autorelease]; self.title = [NSString stringWithUTF8String:title.c_str()];
booWindow = bw; booWindow = bw;
return self; return self;
} }