diff --git a/modules/juce_gui_basics/juce_gui_basics.cpp b/modules/juce_gui_basics/juce_gui_basics.cpp index 518f39397213..89435e3ef6ba 100644 --- a/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/modules/juce_gui_basics/juce_gui_basics.cpp @@ -52,6 +52,10 @@ #import #import +#if defined (MAC_OS_VERSION_14_4) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_14_4 + #import +#endif + #elif JUCE_IOS #if JUCE_PUSH_NOTIFICATIONS #import diff --git a/modules/juce_gui_basics/native/juce_Windowing_mac.mm b/modules/juce_gui_basics/native/juce_Windowing_mac.mm index ad459d483e1a..b559a0f1785d 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_mac.mm +++ b/modules/juce_gui_basics/native/juce_Windowing_mac.mm @@ -520,37 +520,100 @@ static Image createNSWindowSnapshot (NSWindow* nsWindow) { JUCE_AUTORELEASEPOOL { - // CGWindowListCreateImage is replaced by functions in the ScreenCaptureKit framework, but - // that framework is only available from macOS 12.3 onwards. - // A suitable @available check should be added once the minimum build OS is 12.3 or greater, - // so that ScreenCaptureKit can be weak-linked. - #if defined (MAC_OS_VERSION_14_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_14_0 - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") - #define JUCE_DEPRECATION_IGNORED 1 - #endif + const auto createImageFromCGImage = [&] (CGImageRef cgImage) + { + jassert (cgImage != nullptr); - CGImageRef screenShot = CGWindowListCreateImage (CGRectNull, - kCGWindowListOptionIncludingWindow, - (CGWindowID) [nsWindow windowNumber], - kCGWindowImageBoundsIgnoreFraming); + const auto width = CGImageGetWidth (cgImage); + const auto height = CGImageGetHeight (cgImage); + const auto cgRect = CGRectMake (0, 0, (CGFloat) width, (CGFloat) height); + const Image image (Image::ARGB, (int) width, (int) height, true); - #if JUCE_DEPRECATION_IGNORED - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - #undef JUCE_DEPRECATION_IGNORED - #endif + CGContextDrawImage (juce_getImageContext (image), cgRect, cgImage); - NSBitmapImageRep* bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage: screenShot]; + return image; + }; - Image result (Image::ARGB, (int) [bitmapRep size].width, (int) [bitmapRep size].height, true); + #if defined (MAC_OS_VERSION_14_4) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_14_4 - selectImageForDrawing (result); - [bitmapRep drawAtPoint: NSMakePoint (0, 0)]; - releaseImageAfterDrawing(); + if (dlopen ("/System/Library/Frameworks/ScreenCaptureKit.framework/ScreenCaptureKit", RTLD_LAZY) == nullptr) + { + DBG (dlerror()); + jassertfalse; + return {}; + } - [bitmapRep release]; - CGImageRelease (screenShot); + std::promise result; - return result; + const auto windowId = nsWindow.windowNumber; + const auto windowRect = [nsWindow.screen convertRectToBacking: nsWindow.frame].size; + + const auto onSharableContent = [&] (SCShareableContent* content, NSError* contentError) + { + if (contentError != nullptr) + { + jassertfalse; + result.set_value (Image{}); + return; + } + + const auto window = [&]() -> SCWindow* + { + for (SCWindow* w in content.windows) + if (w.windowID == windowId) + return w; + + return nullptr; + }(); + + if (window == nullptr) + { + jassertfalse; + result.set_value (Image{}); + return; + } + + Class contentFilterClass = NSClassFromString (@"SCContentFilter"); + SCContentFilter* filter = [[[contentFilterClass alloc] initWithDesktopIndependentWindow: window] autorelease]; + + Class streamConfigurationClass = NSClassFromString (@"SCStreamConfiguration"); + SCStreamConfiguration* config = [[[streamConfigurationClass alloc] init] autorelease]; + config.colorSpaceName = kCGColorSpaceSRGB; + config.showsCursor = NO; + config.ignoreShadowsSingleWindow = YES; + config.captureResolution = SCCaptureResolutionBest; + config.ignoreGlobalClipSingleWindow = YES; + config.includeChildWindows = NO; + config.width = (size_t) windowRect.width; + config.height = (size_t) windowRect.height; + + const auto onScreenshot = [&] (CGImageRef screenshot, NSError* screenshotError) + { + jassert (screenshotError == nullptr); + result.set_value (screenshotError == nullptr ? createImageFromCGImage (screenshot) : Image{}); + }; + + Class screenshotManagerClass = NSClassFromString (@"SCScreenshotManager"); + [screenshotManagerClass captureImageWithFilter: filter + configuration: config + completionHandler: onScreenshot]; + }; + + Class shareableContentClass = NSClassFromString (@"SCShareableContent"); + [shareableContentClass getCurrentProcessShareableContentWithCompletionHandler: onSharableContent]; + + return result.get_future().get(); + + #else + + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations") + return createImageFromCGImage ((CGImageRef) CFAutorelease (CGWindowListCreateImage (CGRectNull, + kCGWindowListOptionIncludingWindow, + (CGWindowID) [nsWindow windowNumber], + kCGWindowImageBoundsIgnoreFraming))); + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + #endif } }