Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsckcapturablewindows.mm
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/private/qcore_mac_p.h>
7#include <QtCore/private/qexpected_p.h>
8#include <QtCore/qlist.h>
9
10#include <QtFFmpegMediaPluginImpl/private/qmacscreencapturekit_p.h>
11
12#include <QtGui/qwindow.h>
13
14#include <QtMultimedia/private/qcapturablewindow_p.h>
15
16#import <AppKit/NSWindow.h>
17
18#include <algorithm>
19#include <vector>
20
21using namespace Qt::Literals::StringLiterals;
22
23QT_BEGIN_NAMESPACE
24
25namespace QFFmpeg {
26
27// ScreenCaptureKit reports several windows that cannot be captured, or
28// are otherwise just black. Such windows include invidividual icons on
29// the taskbar. Filtering out some of these based on bundle identifier
30// tends to clean up the list.
32 "com.apple.controlcenter",
33 "com.apple.dock",
34 "com.apple.notificationcenterui", };
35
36// Can be called from any thread.
38{
39 QMacAutoReleasePool autoReleasePool;
40
41 // Do a blocking query for ScreenCaptureKit capturable items.
42 q23::expected<QMacScreenCaptureKit::CapturableItems, QString> enumerateResult =
43 QMacScreenCaptureKit::enumerateCapturableItems()
44 .get();
45 if (!enumerateResult) {
46 qCWarning(qLcMacScreenCapture)
47 << "Failed to enumerate capturable windows/displays: "
48 << enumerateResult.error();
49 return {};
50 }
51
52 QMacScreenCaptureKit::CapturableItems const &capturableItems = *enumerateResult;
53
54 QList<QCapturableWindow> result;
55
56 for (AVFScopedPointer<SCWindow> const &window : capturableItems.windows) {
57 // SCWindows with onScreen set to false usually indicates we cannot
58 // capture it at this time, but it might be capturable in the future.
59 if (!window.data().onScreen)
60 continue;
61
62 QString bundleIdentifier = QString::fromNSString(window.data().owningApplication.bundleIdentifier);
63 // An empty bundle-identifier commonly implies this window cannot be captured.
64 if (bundleIdentifier.isEmpty())
65 continue;
66
67 bool bundleIdentifierBlacklisted = std::any_of(
68 windowBundleIdentifierBlacklist.begin(),
69 windowBundleIdentifierBlacklist.end(),
70 [&](const char *identifier) {
71 return QString::fromLatin1(identifier, -1) == bundleIdentifier;
72 });
73 if (bundleIdentifierBlacklisted)
74 continue;
75
76 // No title commonly implies this is not a user-facing window.
77 QString title = QString::fromNSString(window.data().title);
78 if (title.isEmpty())
79 continue;
80
81 result.push_back(QCapturableWindowPrivate::create(
82 static_cast<QCapturableWindowPrivate::Id>(window.data().windowID),
83 std::move(title)));
84 }
85
86 return result;
87}
88
89// Can be called from any thread.
90bool QSckCapturableWindows::isWindowValid(const QCapturableWindowPrivate &window) const
91{
92 QMacAutoReleasePool autoReleasePool;
93
94 if (window.id == 0)
95 return false;
96
97 // Do a blocking query for ScreenCaptureKit capturable items.
98 q23::expected<QMacScreenCaptureKit::CapturableItems, QString> enumerateResult =
99 QMacScreenCaptureKit::enumerateCapturableItems()
100 .get();
101 if (!enumerateResult) {
102 qCWarning(qLcMacScreenCapture)
103 << "Failed to enumerate capturable windows/displays during QSckCapturableWindows::isWindowValid: "
104 << enumerateResult.error();
105 return false;
106 }
107
108 std::vector<AVFScopedPointer<SCWindow>> const &windows = enumerateResult->windows;
109
110 return std::any_of(
111 windows.begin(),
112 windows.end(),
113 [&](AVFScopedPointer<SCWindow> const &item) {
114 return item.data().windowID == static_cast<CGWindowID>(window.id);
115 });
116}
117
118// Can be called from any thread.
120{
121 QMacAutoReleasePool autoReleasePool;
122
123 auto *nsView = reinterpret_cast<NSView*>(window->winId());
124
125 NSWindow *nsWindow = [nsView window];
126 if (nsWindow == nullptr)
127 return q23::unexpected{ QStringLiteral("NSView had no associated NSWindow") };
128
129 auto cgWindowId = (CGWindowID)[nsWindow windowNumber];
130 if (cgWindowId == kCGNullWindowID)
131 return q23::unexpected{ QStringLiteral("NSWindow has no CGWindowID") };
132
133 return QCapturableWindowPrivate::create(
134 static_cast<QCapturableWindowPrivate::Id>(cgWindowId),
135 window->title());
136}
137
139{
140 return std::make_unique<QSckCapturableWindows>();
141}
142
143} // namespace QFFmpeg
144
145QT_END_NAMESPACE
q23::expected< QCapturableWindow, QString > fromQWindow(QWindow *) const override
bool isWindowValid(const QCapturableWindowPrivate &window) const override
QList< QCapturableWindow > windows() const override
QT_MANGLE_NAMESPACE(QMacScreenCaptureStreamDelegate) QMacScreenCaptureStreamDelegate
constexpr std::array windowBundleIdentifierBlacklist
std::unique_ptr< QPlatformCapturableWindows > makeQSckCapturableWindows()