build, libgimpwidgets, meson: Add ScreenCaptureKit support

Inspired by https://github.com/neutralinojs/neutralinojs/pull/1477/changes
which was found by Alex.

This makes possible to build GIMP on macOS 12+ targets, which is
useful for local builds. We, however, will keep targeting macOS 11.
This commit is contained in:
Bruno Lopes 2026-03-28 20:39:57 -03:00
parent 4f1c6a2a8b
commit 2bdc93281c
4 changed files with 77 additions and 3 deletions

View file

@ -28,8 +28,7 @@ if [ -z "$OPT_PREFIX" ]; then
exit 1
fi
fi
#FIXME: remove `echo "$CI_JOB_NAME" | grep -q 'gimp'` after ScreenCaptureKit support
if { [ "$OPT_PREFIX" != '/opt/local' ] && [ "$OPT_PREFIX" != '/opt/homebrew' ] } || echo "$CI_JOB_NAME" | grep -q 'gimp'; then
if [ "$OPT_PREFIX" != '/opt/local' ] && [ "$OPT_PREFIX" != '/opt/homebrew' ]; then
export MACOSX_DEPLOYMENT_TARGET=$(awk '/LSMinimumSystemVersion/{found=1} found && /<string>/{gsub(/.*<string>|<\/string>.*/, ""); print; exit}' build/macos/Info.plist)
echo "macosx_deployment_target ${MACOSX_DEPLOYMENT_TARGET}" | tee -a ${OPT_PREFIX}/etc/macports/macports.conf >/dev/null 2>&1 || true
sed -i .bak "s/^#build_arch.*/build_arch $(uname -m)/" "${OPT_PREFIX}/etc/macports/macports.conf" >/dev/null 2>&1 || true

View file

@ -32,6 +32,9 @@
#include <Carbon/Carbon.h> /* For virtual key codes ... */
#include <ApplicationServices/ApplicationServices.h>
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 120300
#import <ScreenCaptureKit/ScreenCaptureKit.h>
#endif
@interface GimpPickWindowController : NSObject
{
@ -177,10 +180,69 @@
rect = [self.window convertRectToScreen:rect];
rect.origin.y = [[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.origin.y;
root_image_ref = nil;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 120300
/* ScreenCaptureKit is asyncronous */
__block CGImageRef captured_image = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent *monitor_content, NSError *monitor_error) {
if (monitor_error == nil && monitor_content != nil)
{
/* find the monitor that contains the rect.origin where the user clicked */
SCDisplay *target_monitor = monitor_content.displays.firstObject;
for (SCDisplay *monitor in monitor_content.displays)
{
if (CGRectContainsPoint (monitor.frame, rect.origin))
{
target_monitor = monitor;
break;
}
}
/* get the whole monitor, without scaling or anti-aliasing effects */
SCContentFilter *monitor_size = [[SCContentFilter alloc] initWithDisplay:target_monitor excludingWindows:@[]];
SCStreamConfiguration *monitor_config = [[SCStreamConfiguration alloc] init];
monitor_config.scalesToFit = NO;
/* take the actual "screenshot" on the monitor */
[SCScreenshotManager captureImageWithFilter:monitor_size configuration:monitor_config
completionHandler:^(CGImageRef captured_monitor, NSError *captured_error) {
if (captured_error == nil && captured_monitor != NULL)
{
CGRect captured_crop = CGRectMake (rect.origin.x - target_monitor.frame.origin.x,
rect.origin.y - target_monitor.frame.origin.y,
rect.size.width, rect.size.height);
captured_image = CGImageCreateWithImageInRect (captured_monitor, captured_crop);
}
dispatch_semaphore_signal (semaphore);
}];
[monitor_size release];
[monitor_config release];
}
else
{
dispatch_semaphore_signal (semaphore);
}
}];
dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC));
root_image_ref = captured_image;
#else
root_image_ref = CGWindowListCreateImage (rect,
kCGWindowListOptionOnScreenOnly,
kCGNullWindowID,
kCGWindowImageDefault);
#endif
if (root_image_ref == NULL)
{
g_warning ("Failed to capture screen pixels. Permission denied or DRM protected content.");
return;
}
pixel_data = CGDataProviderCopyData (CGImageGetDataProvider (root_image_ref));
data = CFDataGetBytePtr (pixel_data);
@ -441,6 +503,17 @@ _gimp_pick_button_quartz_pick (GimpPickButton *button)
pool = [[NSAutoreleasePool alloc] init];
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 120300
/* Needed for ScreenCaptureKit which is asyncronous */
if (!CGPreflightScreenCaptureAccess())
{
CGRequestScreenCaptureAccess();
[pool release];
return;
}
#endif
controller = [[GimpPickWindowController alloc] initWithButton:button];
[pool release];

View file

@ -207,7 +207,7 @@ libgimpwidgets = library('gimpwidgets-'+ gimp_api_version,
libgimpwidgets_sources,
include_directories: rootInclude,
dependencies: [
gegl, gexiv2, gtk3, lcms, math, mscms
gegl, gexiv2, gtk3, lcms, math, mscms, screencapturekit
],
c_args: [ '-DG_LOG_DOMAIN="LibGimpWidgets"', '-DGIMP_WIDGETS_COMPILATION', ],
link_with: [

View file

@ -432,6 +432,8 @@ dbghelp = platform_windows ? cc.find_library('dbghelp') : no_dep
winsock = platform_windows ? cc.find_library('ws2_32') : no_dep
mscms = platform_windows ? cc.find_library('mscms') : no_dep
screencapturekit = platform_osx ? dependency('appleframeworks', modules: 'ScreenCaptureKit', required: false) : no_dep
atk_minver = '2.4.0'
atk = dependency('atk', version: '>='+atk_minver)
babl_minver = '0.1.118'