From f351f63b58cef2f10ca36581212fe7cb98acb399 Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Fri, 3 Jan 2025 10:49:18 -0500 Subject: [PATCH] Mac deprecation: replace CGWindowListCreateImage by ScreenCaptureKit. Fix unresponsive combo/switch settings --- .../tool/native/DesktopToolsMacOsNative.mm | 81 ++++++++++++++++++- .../Control/Button/Settings/ComboSetting.qml | 4 +- .../Control/Button/Settings/SwitchSetting.qml | 2 +- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/Linphone/tool/native/DesktopToolsMacOsNative.mm b/Linphone/tool/native/DesktopToolsMacOsNative.mm index 7ddc5c56e..e43a15fc5 100644 --- a/Linphone/tool/native/DesktopToolsMacOsNative.mm +++ b/Linphone/tool/native/DesktopToolsMacOsNative.mm @@ -170,10 +170,85 @@ QImage DesktopTools::getWindowIcon(void *window) { } QImage DesktopTools::takeScreenshot(void *window) { - + __block bool haveAccess = false; + // Must be call from main thread! If not, you may be in deadlock. + dispatch_sync(dispatch_get_main_queue(), ^{ + // Checks whether the current process already has screen capture access + haveAccess = CGPreflightScreenCaptureAccess(); + //Requests event listening access if absent, potentially prompting + if(!haveAccess) haveAccess = CGRequestScreenCaptureAccess(); + }); + if(!haveAccess){ + qCritical() << "The application don't have the permission to capture the screen"; + return QImage(); + } + std::condition_variable condition; + std::mutex lock; + BOOL ended = FALSE; + __block SCContentFilter *filter = nil; + __block CGImageRef capture = nil; + __block BOOL *_ended = &ended; + __block std::condition_variable *_condition = &condition; CGWindowID windowId = *(CGWindowID*)&window; - CGImageRef capture = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowId, kCGWindowImageBoundsIgnoreFraming); - return CGImageToQImage(capture); + + [SCShareableContent + getShareableContentWithCompletionHandler:^(SCShareableContent *shareableContent, + NSError *error) { + if (!error || error.code == 0) { + if(windowId) { + for (int i = 0; i < shareableContent.windows.count && !filter; ++i){ + if (shareableContent.windows[i].windowID == windowId) { + filter = [[SCContentFilter alloc] initWithDesktopIndependentWindow:shareableContent.windows[i]]; + } + } + } + }else + qCritical() << "SCShareableContent error: " << error.code; + *_ended = TRUE; + _condition->notify_all(); + }]; + std::unique_lock locker(lock); + condition.wait(locker, [&ended]{ return ended; }); + if(!filter){ + qCritical() << "Screenshot: The filter could not be created"; + return QImage(); + } + *_ended = FALSE; + + SCStreamConfiguration *configuration = [[SCStreamConfiguration alloc] init]; + configuration.capturesAudio = NO; + configuration.excludesCurrentProcessAudio = YES; + configuration.preservesAspectRatio = YES; + configuration.showsCursor = NO; + configuration.captureResolution = SCCaptureResolutionBest; + configuration.width = NSWidth(filter.contentRect) * filter.pointPixelScale; + configuration.height = NSHeight(filter.contentRect) * filter.pointPixelScale; + [SCScreenshotManager captureImageWithFilter:filter + configuration:configuration + completionHandler:^(CGImageRef sampleBuffer, NSError *error){ + if (!error || error.code == 0) { + capture = sampleBuffer; + [capture retain]; + }else{ + qCritical() << "Screenshot: cannot capture: " << error.code; + } + *_ended = TRUE; + _condition->notify_all(); + } + ]; + condition.wait(locker, [&ended]{ return ended; }); + [configuration dealloc]; + [filter dealloc]; + if(!capture) { + return QImage(); + } + QImage image = CGImageToQImage(capture); + [capture release]; + return image; + // Deprecated: + //CGWindowID windowId = *(CGWindowID*)&window; + //CGImageRef capture = CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowId, kCGWindowImageBoundsIgnoreFraming); + //return CGImageToQImage(capture); } diff --git a/Linphone/view/Control/Button/Settings/ComboSetting.qml b/Linphone/view/Control/Button/Settings/ComboSetting.qml index a29a1dd45..838b64ca6 100644 --- a/Linphone/view/Control/Button/Settings/ComboSetting.qml +++ b/Linphone/view/Control/Button/Settings/ComboSetting.qml @@ -28,9 +28,9 @@ ComboBox { } Binding { id: binding - target: propertyOwnerGui ? propertyOwnerGui : propertyOwner + target: propertyOwnerGui ? propertyOwnerGui.core : propertyOwner property: propertyName value: mainItem.currentValue when: false } -} \ No newline at end of file +} diff --git a/Linphone/view/Control/Button/Settings/SwitchSetting.qml b/Linphone/view/Control/Button/Settings/SwitchSetting.qml index 80d586623..31d49ae06 100644 --- a/Linphone/view/Control/Button/Settings/SwitchSetting.qml +++ b/Linphone/view/Control/Button/Settings/SwitchSetting.qml @@ -47,7 +47,7 @@ RowLayout { } Binding { id: binding - target: propertyOwnerGui ? propertyOwnerGui : propertyOwner ? propertyOwner : null + target: propertyOwnerGui ? propertyOwnerGui.core : propertyOwner ? propertyOwner : null property: mainItem.propertyName value: switchButton.checked when: false