Skip to content

Commit 9736f9f

Browse files
Merge pull request #1688 from nolankramer/master
Fix macOS window embedding
2 parents 1254c31 + 876ee20 commit 9736f9f

2 files changed

Lines changed: 65 additions & 12 deletions

File tree

include/vsg/platform/macos/MacOS_Window.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ namespace vsgMacOS
5757

5858
const char* instanceExtensionSurfaceName() const override { return "VK_MVK_macos_surface"; }
5959

60-
bool valid() const override { return _window; }
60+
bool valid() const override { return _window || _view; }
6161

6262
bool pollEvents(vsg::UIEvents& events) override;
6363

src/vsg/platform/macos/MacOS_Window.mm

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -708,10 +708,58 @@ void createApplicationMenus(void)
708708
}
709709

710710
MacOS_Window::MacOS_Window(vsg::ref_ptr<vsg::WindowTraits> traits) :
711-
Inherit(traits)
711+
Inherit(traits),
712+
_window(nil),
713+
_view(nil),
714+
_metalLayer(nil)
712715
{
713716
_keyboard = new KeyboardMap;
714717

718+
// When nativeWindow is set, embed into the provided NSView rather than
719+
// creating a standalone NSWindow. This mirrors Win32_Window's handling
720+
// of an external HWND.
721+
if (traits->nativeWindow.has_value())
722+
{
723+
auto nativeHandle = std::any_cast<unsigned long long>(traits->nativeWindow);
724+
if (nativeHandle)
725+
{
726+
NSView* externalView = reinterpret_cast<NSView*>(nativeHandle);
727+
_view = (vsg_MacOS_NSView*)externalView;
728+
[_view setWantsLayer:YES];
729+
730+
_metalLayer = (CAMetalLayer*)[_view layer];
731+
if (!_metalLayer || ![_metalLayer isKindOfClass:[CAMetalLayer class]])
732+
{
733+
_metalLayer = [[CAMetalLayer alloc] init];
734+
if (!_metalLayer)
735+
{
736+
throw Exception{"Error: vsg::MacOS_Window::MacOS_Window(...) failed to create CAMetalLayer for embedded view.", VK_ERROR_INVALID_EXTERNAL_HANDLE};
737+
}
738+
[_view setLayer:_metalLayer];
739+
}
740+
741+
auto devicePixelScale = _traits->hdpi ? [[_view window] backingScaleFactor] : 1.0f;
742+
[_metalLayer setContentsScale:devicePixelScale];
743+
744+
uint32_t finalwidth = traits->width * devicePixelScale;
745+
uint32_t finalheight = traits->height * devicePixelScale;
746+
747+
if (traits->device) share(traits->device);
748+
749+
_extent2D.width = finalwidth;
750+
_extent2D.height = finalheight;
751+
752+
_first_macos_timestamp = [[NSProcessInfo processInfo] systemUptime];
753+
_first_macos_time_point = vsg::clock::now();
754+
755+
vsg::clock::time_point event_time = vsg::clock::now();
756+
bufferedEvents.emplace_back(vsg::ConfigureWindowEvent::create(this, event_time, _traits->x, _traits->y, finalwidth, finalheight));
757+
758+
return;
759+
}
760+
}
761+
762+
// Standalone window path
715763
NSRect contentRect = NSMakeRect(0, 0, traits->width, traits->height);
716764

717765
NSWindowStyleMask styleMask = 0;
@@ -822,16 +870,20 @@ void createApplicationMenus(void)
822870

823871
bool MacOS_Window::pollEvents(vsg::UIEvents& events)
824872
{
825-
for (;;)
873+
// Skip NSApp event polling when embedded — the host owns the event loop.
874+
if (_window)
826875
{
827-
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
828-
untilDate:[NSDate distantPast]
829-
inMode:NSDefaultRunLoopMode
830-
dequeue:YES];
831-
if (event == nil)
832-
break;
833-
834-
[NSApp sendEvent:event];
876+
for (;;)
877+
{
878+
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
879+
untilDate:[NSDate distantPast]
880+
inMode:NSDefaultRunLoopMode
881+
dequeue:YES];
882+
if (event == nil)
883+
break;
884+
885+
[NSApp sendEvent:event];
886+
}
835887
}
836888

837889
return Window::pollEvents(events);
@@ -841,7 +893,8 @@ void createApplicationMenus(void)
841893
{
842894
const NSRect contentRect = [_view frame];
843895

844-
auto devicePixelScale = _traits->hdpi ? [_window backingScaleFactor] : 1.0f;
896+
NSWindow* hostWindow = _window ? _window : [_view window];
897+
auto devicePixelScale = _traits->hdpi ? [hostWindow backingScaleFactor] : 1.0f;
845898
//[_metalLayer setContentsScale:devicePixelScale];
846899

847900
_extent2D.width = contentRect.size.width * devicePixelScale;

0 commit comments

Comments
 (0)