mirror of
https://github.com/AxioDL/boo.git
synced 2025-06-25 07:53:41 +00:00
shared_ptr for IWindow; better Cocoa app lifecycle
This commit is contained in:
parent
49afde2fb9
commit
b97c82469a
@ -51,7 +51,7 @@ public:
|
|||||||
virtual const std::vector<SystemString>& getArgs() const=0;
|
virtual const std::vector<SystemString>& getArgs() const=0;
|
||||||
|
|
||||||
/* Constructors/initializers for sub-objects */
|
/* Constructors/initializers for sub-objects */
|
||||||
virtual IWindow* newWindow(const SystemString& title, uint32_t drawSamples)=0;
|
virtual std::shared_ptr<IWindow> newWindow(const SystemString& title, uint32_t drawSamples)=0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -254,14 +254,15 @@ enum class EClipboardType
|
|||||||
PNGImage = 3
|
PNGImage = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
class IWindow
|
class IWindow : public std::enable_shared_from_this<IWindow>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~IWindow() {}
|
virtual ~IWindow() = default;
|
||||||
|
|
||||||
virtual void setCallback(IWindowCallback* cb)=0;
|
virtual void setCallback(IWindowCallback* cb)=0;
|
||||||
|
|
||||||
|
virtual void closeWindow()=0;
|
||||||
virtual void showWindow()=0;
|
virtual void showWindow()=0;
|
||||||
virtual void hideWindow()=0;
|
virtual void hideWindow()=0;
|
||||||
|
|
||||||
|
@ -11,6 +11,12 @@
|
|||||||
#error ARC Required
|
#error ARC Required
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* If set, application will terminate once client thread reaches end;
|
||||||
|
* main() will not get back control. Otherwise, main will get back control
|
||||||
|
* but App will not terminate in the normal Cocoa manner (possibly resulting
|
||||||
|
* in CoreAnimation warnings). */
|
||||||
|
#define COCOA_TERMINATE 1
|
||||||
|
|
||||||
namespace boo {class ApplicationCocoa;}
|
namespace boo {class ApplicationCocoa;}
|
||||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||||
{
|
{
|
||||||
@ -24,7 +30,7 @@ namespace boo
|
|||||||
{
|
{
|
||||||
static logvisor::Module Log("boo::ApplicationCocoa");
|
static logvisor::Module Log("boo::ApplicationCocoa");
|
||||||
|
|
||||||
IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
|
std::shared_ptr<IWindow> _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
|
||||||
MetalContext* metalCtx, uint32_t sampleCount);
|
MetalContext* metalCtx, uint32_t sampleCount);
|
||||||
|
|
||||||
class ApplicationCocoa : public IApplication
|
class ApplicationCocoa : public IApplication
|
||||||
@ -41,7 +47,7 @@ private:
|
|||||||
NSPanel* aboutPanel;
|
NSPanel* aboutPanel;
|
||||||
|
|
||||||
/* All windows */
|
/* All windows */
|
||||||
std::unordered_map<uintptr_t, IWindow*> m_windows;
|
std::unordered_map<uintptr_t, std::weak_ptr<IWindow>> m_windows;
|
||||||
|
|
||||||
MetalContext m_metalCtx;
|
MetalContext m_metalCtx;
|
||||||
|
|
||||||
@ -108,6 +114,7 @@ public:
|
|||||||
|
|
||||||
std::thread m_clientThread;
|
std::thread m_clientThread;
|
||||||
int m_clientReturn = 0;
|
int m_clientReturn = 0;
|
||||||
|
bool m_terminateNow = false;
|
||||||
int run()
|
int run()
|
||||||
{
|
{
|
||||||
/* Spawn client thread */
|
/* Spawn client thread */
|
||||||
@ -118,11 +125,30 @@ public:
|
|||||||
/* Run app */
|
/* Run app */
|
||||||
m_clientReturn = m_callback.appMain(this);
|
m_clientReturn = m_callback.appMain(this);
|
||||||
|
|
||||||
/* Cleanup here */
|
/* Cleanup */
|
||||||
std::vector<std::unique_ptr<IWindow>> toDelete;
|
for (auto& w : m_windows)
|
||||||
toDelete.reserve(m_windows.size());
|
if (std::shared_ptr<IWindow> window = w.second.lock())
|
||||||
for (auto& window : m_windows)
|
window->closeWindow();
|
||||||
toDelete.emplace_back(window.second);
|
|
||||||
|
#if COCOA_TERMINATE
|
||||||
|
/* Continue termination */
|
||||||
|
dispatch_sync(dispatch_get_main_queue(),
|
||||||
|
^{
|
||||||
|
/* Ends modal run loop and continues Cocoa termination */
|
||||||
|
[[NSApplication sharedApplication] replyToApplicationShouldTerminate:YES];
|
||||||
|
|
||||||
|
/* If this is reached, application didn't spawn any windows
|
||||||
|
* and must be explicitly terminated */
|
||||||
|
m_terminateNow = true;
|
||||||
|
[[NSApplication sharedApplication] terminate:nil];
|
||||||
|
});
|
||||||
|
#else
|
||||||
|
/* Return control to main() */
|
||||||
|
dispatch_sync(dispatch_get_main_queue(),
|
||||||
|
^{
|
||||||
|
[[NSApplication sharedApplication] stop:nil];
|
||||||
|
});
|
||||||
|
#endif
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Already in Cocoa's event loop; return now */
|
/* Already in Cocoa's event loop; return now */
|
||||||
@ -154,9 +180,9 @@ public:
|
|||||||
return m_args;
|
return m_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWindow* newWindow(const std::string& title, uint32_t sampleCount)
|
std::shared_ptr<IWindow> newWindow(const std::string& title, uint32_t sampleCount)
|
||||||
{
|
{
|
||||||
IWindow* newWindow = _WindowCocoaNew(title, m_lastGLCtx, &m_metalCtx, sampleCount);
|
auto newWindow = _WindowCocoaNew(title, m_lastGLCtx, &m_metalCtx, sampleCount);
|
||||||
m_windows[newWindow->getPlatformHandle()] = newWindow;
|
m_windows[newWindow->getPlatformHandle()] = newWindow;
|
||||||
return newWindow;
|
return newWindow;
|
||||||
}
|
}
|
||||||
@ -187,10 +213,14 @@ int ApplicationRun(IApplication::EPlatformType platform,
|
|||||||
if (platform != IApplication::EPlatformType::Cocoa &&
|
if (platform != IApplication::EPlatformType::Cocoa &&
|
||||||
platform != IApplication::EPlatformType::Auto)
|
platform != IApplication::EPlatformType::Auto)
|
||||||
return 1;
|
return 1;
|
||||||
|
/* Never deallocated to ensure window destructors have access */
|
||||||
APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args);
|
APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args);
|
||||||
}
|
}
|
||||||
[[NSApplication sharedApplication] run];
|
[[NSApplication sharedApplication] run];
|
||||||
return static_cast<ApplicationCocoa*>(APP)->m_clientReturn;
|
ApplicationCocoa* appCocoa = static_cast<ApplicationCocoa*>(APP);
|
||||||
|
if (appCocoa->m_clientThread.joinable())
|
||||||
|
appCocoa->m_clientThread.join();
|
||||||
|
return appCocoa->m_clientReturn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,12 +238,23 @@ int ApplicationRun(IApplication::EPlatformType platform,
|
|||||||
(void)notification;
|
(void)notification;
|
||||||
m_app->run();
|
m_app->run();
|
||||||
}
|
}
|
||||||
- (void)applicationWillTerminate:(NSNotification*)notification
|
#if COCOA_TERMINATE
|
||||||
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app
|
||||||
{
|
{
|
||||||
(void)notification;
|
(void)app;
|
||||||
|
if (m_app->m_terminateNow)
|
||||||
|
return NSTerminateNow;
|
||||||
m_app->m_callback.appQuitting(m_app);
|
m_app->m_callback.appQuitting(m_app);
|
||||||
m_app->m_clientThread.join();
|
return NSTerminateLater;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app
|
||||||
|
{
|
||||||
|
(void)app;
|
||||||
|
m_app->m_callback.appQuitting(m_app);
|
||||||
|
return NSTerminateCancel;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename
|
- (BOOL)application:(NSApplication*)sender openFile:(NSString*)filename
|
||||||
{
|
{
|
||||||
std::vector<boo::SystemString> strVec;
|
std::vector<boo::SystemString> strVec;
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
namespace boo {class WindowCocoa; class GraphicsContextCocoa;}
|
namespace boo {class WindowCocoa; class GraphicsContextCocoa;}
|
||||||
@interface WindowCocoaInternal : NSWindow
|
@interface WindowCocoaInternal : NSWindow
|
||||||
{
|
{
|
||||||
boo::WindowCocoa* booWindow;
|
std::shared_ptr<boo::WindowCocoa> booWindow;
|
||||||
id touchBarProvider;
|
id touchBarProvider;
|
||||||
}
|
}
|
||||||
- (id)initWithBooWindow:(boo::WindowCocoa*)bw title:(const std::string&)title;
|
- (id)initWithBooWindow:(std::shared_ptr<boo::WindowCocoa>&)bw title:(const std::string&)title;
|
||||||
- (void)setFrameDefault;
|
- (void)setFrameDefault;
|
||||||
- (NSRect)genFrameDefault;
|
- (NSRect)genFrameDefault;
|
||||||
- (void)setTouchBarProvider:(id)provider;
|
- (void)setTouchBarProvider:(id)provider;
|
||||||
@ -218,6 +218,7 @@ public:
|
|||||||
m_dataFactory->destroyAllData();
|
m_dataFactory->destroyAllData();
|
||||||
delete m_commandQueue;
|
delete m_commandQueue;
|
||||||
delete m_dataFactory;
|
delete m_dataFactory;
|
||||||
|
printf("CONTEXT DESTROYED\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setCallback(IWindowCallback* cb)
|
void _setCallback(IWindowCallback* cb)
|
||||||
@ -1266,19 +1267,19 @@ static NSString* ClipboardTypes[] =
|
|||||||
|
|
||||||
class WindowCocoa : public IWindow
|
class WindowCocoa : public IWindow
|
||||||
{
|
{
|
||||||
|
|
||||||
WindowCocoaInternal* m_nsWindow;
|
WindowCocoaInternal* m_nsWindow;
|
||||||
GraphicsContextCocoa* m_gfxCtx;
|
GraphicsContextCocoa* m_gfxCtx;
|
||||||
EMouseCursor m_cursor = EMouseCursor::None;
|
EMouseCursor m_cursor = EMouseCursor::None;
|
||||||
bool m_closed = false;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
WindowCocoa(const std::string& title, NSOpenGLContext* lastGLCtx, MetalContext* metalCtx, uint32_t sampleCount)
|
void setup(const std::string& title, NSOpenGLContext* lastGLCtx, MetalContext* metalCtx, uint32_t sampleCount)
|
||||||
{
|
{
|
||||||
dispatch_sync(dispatch_get_main_queue(),
|
dispatch_sync(dispatch_get_main_queue(),
|
||||||
^{
|
^{
|
||||||
m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:this title:title];
|
std::shared_ptr<boo::WindowCocoa> windowPtr =
|
||||||
|
std::static_pointer_cast<boo::WindowCocoa>(shared_from_this());
|
||||||
|
m_nsWindow = [[WindowCocoaInternal alloc] initWithBooWindow:windowPtr title:title];
|
||||||
#if BOO_HAS_METAL
|
#if BOO_HAS_METAL
|
||||||
if (metalCtx->m_dev)
|
if (metalCtx->m_dev)
|
||||||
m_gfxCtx = static_cast<GraphicsContextCocoa*>(_GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal,
|
m_gfxCtx = static_cast<GraphicsContextCocoa*>(_GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal,
|
||||||
@ -1293,14 +1294,11 @@ public:
|
|||||||
|
|
||||||
void _clearWindow()
|
void _clearWindow()
|
||||||
{
|
{
|
||||||
m_closed = true;
|
m_nsWindow = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
~WindowCocoa()
|
~WindowCocoa()
|
||||||
{
|
{
|
||||||
if (!m_closed)
|
|
||||||
[m_nsWindow orderOut:nil];
|
|
||||||
delete m_gfxCtx;
|
|
||||||
APP->_deletedWindow(this);
|
APP->_deletedWindow(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1309,6 +1307,14 @@ public:
|
|||||||
m_gfxCtx->_setCallback(cb);
|
m_gfxCtx->_setCallback(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void closeWindow()
|
||||||
|
{
|
||||||
|
dispatch_sync(dispatch_get_main_queue(),
|
||||||
|
^{
|
||||||
|
[m_nsWindow close];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void showWindow()
|
void showWindow()
|
||||||
{
|
{
|
||||||
dispatch_sync(dispatch_get_main_queue(),
|
dispatch_sync(dispatch_get_main_queue(),
|
||||||
@ -1331,15 +1337,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setTitle(const std::string& title)
|
void setTitle(const std::string& title)
|
||||||
{
|
|
||||||
if (!m_closed)
|
|
||||||
{
|
{
|
||||||
dispatch_sync(dispatch_get_main_queue(),
|
dispatch_sync(dispatch_get_main_queue(),
|
||||||
^{
|
^{
|
||||||
[m_nsWindow setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
[m_nsWindow setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void setCursor(EMouseCursor cursor)
|
void setCursor(EMouseCursor cursor)
|
||||||
{
|
{
|
||||||
@ -1555,16 +1558,18 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
|
std::shared_ptr<IWindow> _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
|
||||||
MetalContext* metalCtx, uint32_t sampleCount)
|
MetalContext* metalCtx, uint32_t sampleCount)
|
||||||
{
|
{
|
||||||
return new WindowCocoa(title, lastGLCtx, metalCtx, sampleCount);
|
auto ret = std::make_shared<WindowCocoa>();
|
||||||
|
ret->setup(title, lastGLCtx, metalCtx, sampleCount);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation WindowCocoaInternal
|
@implementation WindowCocoaInternal
|
||||||
- (id)initWithBooWindow:(boo::WindowCocoa *)bw title:(const boo::SystemString&)title
|
- (id)initWithBooWindow:(std::shared_ptr<boo::WindowCocoa>&)bw title:(const boo::SystemString&)title
|
||||||
{
|
{
|
||||||
self = [self initWithContentRect:[self genFrameDefault]
|
self = [self initWithContentRect:[self genFrameDefault]
|
||||||
styleMask:NSWindowStyleMaskTitled|
|
styleMask:NSWindowStyleMaskTitled|
|
||||||
@ -1603,8 +1608,8 @@ IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
|
|||||||
}
|
}
|
||||||
- (void)close
|
- (void)close
|
||||||
{
|
{
|
||||||
booWindow->_clearWindow();
|
|
||||||
[super close];
|
[super close];
|
||||||
|
booWindow->_clearWindow();
|
||||||
}
|
}
|
||||||
- (BOOL)acceptsFirstResponder
|
- (BOOL)acceptsFirstResponder
|
||||||
{
|
{
|
||||||
|
@ -202,7 +202,7 @@ struct CTestWindowCallback : IWindowCallback
|
|||||||
|
|
||||||
struct TestApplicationCallback : IApplicationCallback
|
struct TestApplicationCallback : IApplicationCallback
|
||||||
{
|
{
|
||||||
IWindow* mainWindow;
|
std::shared_ptr<IWindow> mainWindow;
|
||||||
boo::TestDeviceFinder devFinder;
|
boo::TestDeviceFinder devFinder;
|
||||||
CTestWindowCallback windowCallback;
|
CTestWindowCallback windowCallback;
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user