diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2024-06-12 15:52:37 +0200 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2024-06-14 11:55:53 +0200 |
| commit | 7d98413d4621b964105f346d9e5a2361a0ce9bfc (patch) | |
| tree | 56b6250e379217a67b5b67f71cd4d6409aa53557 /src/Fl_cocoa.mm | |
| parent | 7104746413c6327d82340dede4abd06bb65f9032 (diff) | |
macOS 15.0 Sequoia: fix capture of window titlebars
The previous procedure using CGWindowListCreateImageFromArray()
is obsoleted in macOS 15.0 .
The new procedure requires an additional framework: ScreenCaptureKit;
FLTK uses it only for macOS ≥ 15.0
Diffstat (limited to 'src/Fl_cocoa.mm')
| -rw-r--r-- | src/Fl_cocoa.mm | 74 |
1 files changed, 71 insertions, 3 deletions
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm index 3283143c2..08be3aef7 100644 --- a/src/Fl_cocoa.mm +++ b/src/Fl_cocoa.mm @@ -1,7 +1,7 @@ // // macOS-Cocoa specific code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -49,6 +49,9 @@ extern "C" { #include <pwd.h> #import <Cocoa/Cocoa.h> +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_15_0 +# import <ScreenCaptureKit/ScreenCaptureKit.h> +#endif // #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING #ifdef DEBUG_SELECT @@ -4607,20 +4610,85 @@ int Fl_Cocoa_Window_Driver::decorated_h() return h() + bt/s; } +#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_15_0 + +// Requires -framework ScreenCaptureKit and used by FLTK for macOS ≥ 15.0 +static CGImageRef capture_titlebar_macOS15(NSWindow *nswin) { + __block CGImageRef capture = NULL; + __block BOOL capture_err = NO; + void (^block_to_stop_main_loop)(void) = ^{ CFRunLoopStop(CFRunLoopGetMain()); }; + CGWindowID target_id = [nswin windowNumber]; + NSRect r = [nswin frame]; + int W = r.size.width, H = r.size.height; + [SCShareableContent getCurrentProcessShareableContentWithCompletionHandler: // macOS 14.4 + ^(SCShareableContent *shareableContent, NSError *error) { + SCWindow *scwin = nil; + if (!error) { + NSEnumerator *enumerator = [[shareableContent windows] objectEnumerator]; + while ((scwin = (SCWindow*)[enumerator nextObject]) != nil) { + if ([scwin windowID] == target_id) { + break; + } + } + } + if (!scwin) { + capture_err = YES; + dispatch_async(dispatch_get_main_queue(), block_to_stop_main_loop); + return; + } + SCContentFilter *filter = [[[SCContentFilter alloc] initWithDesktopIndependentWindow:scwin] autorelease]; + int s = (int)[filter pointPixelScale]; + SCStreamConfiguration *config = [[[SCStreamConfiguration alloc] init] autorelease]; + [config setIgnoreShadowsSingleWindow:YES]; + [config setWidth:W*s]; + [config setHeight:H*s]; + [config setIncludeChildWindows:NO]; // macOS 14.2 + [SCScreenshotManager captureImageWithFilter:filter + configuration:config + completionHandler:^(CGImageRef sampleBuffer, NSError *error) { + if (error) capture_err = YES; + else { + capture = sampleBuffer; + CGImageRetain(capture); + } + dispatch_async(dispatch_get_main_queue(), block_to_stop_main_loop); + } + ]; + } + ]; + // run the main loop until the 1 or 2 blocks above have finished and have stopped the loop + while (!capture_err && !capture) CFRunLoopRun(); + if (capture_err) return NULL; + int bt = [nswin frame].size.height - [[nswin contentView] frame].size.height; + int s = CGImageGetWidth(capture) / W; + CGRect cgr = CGRectMake(0, 0, W * s, bt * s); + CGImageRef title_bar = CGImageCreateWithImageInRect(capture, cgr); + CGImageRelease(capture); + return title_bar; +} +#endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_15_0 + + void Fl_Cocoa_Window_Driver::draw_titlebar_to_context(CGContextRef gc, int w, int h) { FLWindow *nswin = fl_xid(pWindow); if ([nswin canBecomeMainWindow]) [nswin makeMainWindow]; [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:nil inMode:NSDefaultRunLoopMode dequeue:NO]; - CGImageRef img; + CGImageRef img = NULL; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - if (fl_mac_os_version >= 100600) { // verified OK from 10.6 +# if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_15_0 + if (fl_mac_os_version >= 150000) img = capture_titlebar_macOS15(nswin); + else +# endif + if (fl_mac_os_version >= 100600) { // verified OK from 10.6 NSInteger win_id = [nswin windowNumber]; CFArrayRef array = CFArrayCreate(NULL, (const void**)&win_id, 1, NULL); CGRect rr = NSRectToCGRect([nswin frame]); rr.origin.y = CGDisplayBounds(CGMainDisplayID()).size.height - (rr.origin.y + rr.size.height); rr.size.height = h; +# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_15_0 img = CGWindowListCreateImageFromArray(rr, array, kCGWindowImageBoundsIgnoreFraming); // 10.5 +# endif CFRelease(array); } else #endif |
