summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2024-06-12 15:52:37 +0200
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2024-06-14 11:55:53 +0200
commit7d98413d4621b964105f346d9e5a2361a0ce9bfc (patch)
tree56b6250e379217a67b5b67f71cd4d6409aa53557 /src
parent7104746413c6327d82340dede4abd06bb65f9032 (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')
-rw-r--r--src/Fl_Widget_Surface.cxx2
-rw-r--r--src/Fl_cocoa.mm74
2 files changed, 72 insertions, 4 deletions
diff --git a/src/Fl_Widget_Surface.cxx b/src/Fl_Widget_Surface.cxx
index f489897ba..98cc736ad 100644
--- a/src/Fl_Widget_Surface.cxx
+++ b/src/Fl_Widget_Surface.cxx
@@ -198,7 +198,7 @@ int Fl_Widget_Surface::printable_rect(int *w, int *h) {return 1;}
void Fl_Widget_Surface::draw_decorated_window(Fl_Window *win, int win_offset_x, int win_offset_y)
{
Fl_RGB_Image *top=0, *left=0, *bottom=0, *right=0;
- if (win->border() && !win->parent()) {
+ if (win->shown() && win->border() && !win->parent()) {
Fl_Window_Driver::driver(win)->capture_titlebar_and_borders(top, left, bottom, right);
}
bool need_push = !is_current();
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