mirror of
https://github.com/AxioDL/boo.git
synced 2025-06-24 15:33:46 +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;
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
class IWindow
|
||||
class IWindow : public std::enable_shared_from_this<IWindow>
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~IWindow() {}
|
||||
virtual ~IWindow() = default;
|
||||
|
||||
virtual void setCallback(IWindowCallback* cb)=0;
|
||||
|
||||
virtual void closeWindow()=0;
|
||||
virtual void showWindow()=0;
|
||||
virtual void hideWindow()=0;
|
||||
|
||||
|
@ -11,6 +11,12 @@
|
||||
#error ARC Required
|
||||
#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;}
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
{
|
||||
@ -24,7 +30,7 @@ namespace boo
|
||||
{
|
||||
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);
|
||||
|
||||
class ApplicationCocoa : public IApplication
|
||||
@ -41,7 +47,7 @@ private:
|
||||
NSPanel* aboutPanel;
|
||||
|
||||
/* All windows */
|
||||
std::unordered_map<uintptr_t, IWindow*> m_windows;
|
||||
std::unordered_map<uintptr_t, std::weak_ptr<IWindow>> m_windows;
|
||||
|
||||
MetalContext m_metalCtx;
|
||||
|
||||
@ -108,6 +114,7 @@ public:
|
||||
|
||||
std::thread m_clientThread;
|
||||
int m_clientReturn = 0;
|
||||
bool m_terminateNow = false;
|
||||
int run()
|
||||
{
|
||||
/* Spawn client thread */
|
||||
@ -118,11 +125,30 @@ public:
|
||||
/* Run app */
|
||||
m_clientReturn = m_callback.appMain(this);
|
||||
|
||||
/* Cleanup here */
|
||||
std::vector<std::unique_ptr<IWindow>> toDelete;
|
||||
toDelete.reserve(m_windows.size());
|
||||
for (auto& window : m_windows)
|
||||
toDelete.emplace_back(window.second);
|
||||
/* Cleanup */
|
||||
for (auto& w : m_windows)
|
||||
if (std::shared_ptr<IWindow> window = w.second.lock())
|
||||
window->closeWindow();
|
||||
|
||||
#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 */
|
||||
@ -154,9 +180,9 @@ public:
|
||||
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;
|
||||
return newWindow;
|
||||
}
|
||||
@ -187,10 +213,14 @@ int ApplicationRun(IApplication::EPlatformType platform,
|
||||
if (platform != IApplication::EPlatformType::Cocoa &&
|
||||
platform != IApplication::EPlatformType::Auto)
|
||||
return 1;
|
||||
/* Never deallocated to ensure window destructors have access */
|
||||
APP = new ApplicationCocoa(cb, uniqueName, friendlyName, pname, args);
|
||||
}
|
||||
[[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;
|
||||
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_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
|
||||
{
|
||||
std::vector<boo::SystemString> strVec;
|
||||
|
@ -17,10 +17,10 @@
|
||||
namespace boo {class WindowCocoa; class GraphicsContextCocoa;}
|
||||
@interface WindowCocoaInternal : NSWindow
|
||||
{
|
||||
boo::WindowCocoa* booWindow;
|
||||
std::shared_ptr<boo::WindowCocoa> booWindow;
|
||||
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;
|
||||
- (NSRect)genFrameDefault;
|
||||
- (void)setTouchBarProvider:(id)provider;
|
||||
@ -218,6 +218,7 @@ public:
|
||||
m_dataFactory->destroyAllData();
|
||||
delete m_commandQueue;
|
||||
delete m_dataFactory;
|
||||
printf("CONTEXT DESTROYED\n");
|
||||
}
|
||||
|
||||
void _setCallback(IWindowCallback* cb)
|
||||
@ -1266,19 +1267,19 @@ static NSString* ClipboardTypes[] =
|
||||
|
||||
class WindowCocoa : public IWindow
|
||||
{
|
||||
|
||||
WindowCocoaInternal* m_nsWindow;
|
||||
GraphicsContextCocoa* m_gfxCtx;
|
||||
EMouseCursor m_cursor = EMouseCursor::None;
|
||||
bool m_closed = false;
|
||||
|
||||
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(),
|
||||
^{
|
||||
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 (metalCtx->m_dev)
|
||||
m_gfxCtx = static_cast<GraphicsContextCocoa*>(_GraphicsContextCocoaMetalNew(IGraphicsContext::EGraphicsAPI::Metal,
|
||||
@ -1293,14 +1294,11 @@ public:
|
||||
|
||||
void _clearWindow()
|
||||
{
|
||||
m_closed = true;
|
||||
m_nsWindow = nullptr;
|
||||
}
|
||||
|
||||
~WindowCocoa()
|
||||
{
|
||||
if (!m_closed)
|
||||
[m_nsWindow orderOut:nil];
|
||||
delete m_gfxCtx;
|
||||
APP->_deletedWindow(this);
|
||||
}
|
||||
|
||||
@ -1309,6 +1307,14 @@ public:
|
||||
m_gfxCtx->_setCallback(cb);
|
||||
}
|
||||
|
||||
void closeWindow()
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(),
|
||||
^{
|
||||
[m_nsWindow close];
|
||||
});
|
||||
}
|
||||
|
||||
void showWindow()
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(),
|
||||
@ -1331,15 +1337,12 @@ public:
|
||||
}
|
||||
|
||||
void setTitle(const std::string& title)
|
||||
{
|
||||
if (!m_closed)
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(),
|
||||
^{
|
||||
[m_nsWindow setTitle:[NSString stringWithUTF8String:title.c_str()]];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return new WindowCocoa(title, lastGLCtx, metalCtx, sampleCount);
|
||||
auto ret = std::make_shared<WindowCocoa>();
|
||||
ret->setup(title, lastGLCtx, metalCtx, sampleCount);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@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]
|
||||
styleMask:NSWindowStyleMaskTitled|
|
||||
@ -1603,8 +1608,8 @@ IWindow* _WindowCocoaNew(const SystemString& title, NSOpenGLContext* lastGLCtx,
|
||||
}
|
||||
- (void)close
|
||||
{
|
||||
booWindow->_clearWindow();
|
||||
[super close];
|
||||
booWindow->_clearWindow();
|
||||
}
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
|
@ -202,7 +202,7 @@ struct CTestWindowCallback : IWindowCallback
|
||||
|
||||
struct TestApplicationCallback : IApplicationCallback
|
||||
{
|
||||
IWindow* mainWindow;
|
||||
std::shared_ptr<IWindow> mainWindow;
|
||||
boo::TestDeviceFinder devFinder;
|
||||
CTestWindowCallback windowCallback;
|
||||
bool running = true;
|
||||
|
Loading…
x
Reference in New Issue
Block a user