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
qohosplatformscreen.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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
4#include <QtCore/qdebug.h>
5#include <QtCore/qdatetime.h>
6
7#include <qpa/qwindowsysteminterface.h>
8
9#include <qohosdisplayinfo.h>
14#include "qohosjsmain.h"
16#include "render/qohosview.h"
17#include <algorithm>
18#include <multimedia/image_framework/image/pixelmap_native.h>
19#include <optional>
20#include <qarkui/qarkuiutils.h>
21#include <qohosapppermissions_p.h>
22#include <qohosjsutils.h>
23#include <QtGui/private/qohosimageconversions_p.h>
24#include <qohospixelmapconversions.h>
25#include <qohosutils.h>
26#include <render/qwindowproxyregistry.h>
27#include <window_manager/oh_display_capture.h>
28
29#include <QtGui/qguiapplication.h>
30#include <QtGui/qwindow.h>
31#include <QtCore/private/qnapi_p.h>
32#include <QtCore/private/qohoslogger_p.h>
33#include <QtGui/private/qhighdpiscaling_p.h>
34#include <QtGui/private/qwindow_p.h>
35
36#include <vector>
37
39
40namespace {
41
42static const int ohosLogicalDpi = 72;
43
45 QtOhos::JsState &, QOhosDisplayInfo::JsDisplayId displayId)
46{
47 ::OH_PixelmapNative *pixelMapNativePtr;
48
49 QArkUi::callArkUiOrFailOnErrorResult(
50 Q_OHOS_NAMED_FUNC(::OH_NativeDisplayManager_CaptureScreenPixelmap),
51 static_cast<std::uint32_t>(displayId.value()), &pixelMapNativePtr);
52
53 return wrapOhosNativePixelMapPtr(pixelMapNativePtr);
54}
55
57 QtOhos::JsState &jsState, QOhosDisplayInfo::JsDisplayId displayId,
58 QOhosConsumer<std::shared_ptr<::OH_PixelmapNative>> pixelMapOrNullConsumer)
59{
60 static constexpr const char *ohosCustomScreenCapturePermission =
61 "ohos.permission.CUSTOM_SCREEN_CAPTURE";
62
64 jsState, ohosCustomScreenCapturePermission,
65 [pixelMapOrNullConsumer = std::move(pixelMapOrNullConsumer), displayId](
66 auto &jsState, bool permissionGranted) {
67 if (permissionGranted) {
68 pixelMapOrNullConsumer(captureScreenPixelmap(jsState, displayId));
69 } else {
70 qOhosPrintfError(
71 "%s: %s hasn't been granted by user. Cannot grab window.", Q_FUNC_INFO,
72 ohosCustomScreenCapturePermission);
73 pixelMapOrNullConsumer(nullptr);
74 }
75 });
76}
77
79{
80 auto allWindows = qApp->allWindows();
81 auto windowItByWId = std::find_if(
82 std::begin(allWindows), std::end(allWindows),
83 [&](QWindow *w) {
84 return w->winId() == wId;
85 });
86
87 if (windowItByWId == allWindows.end())
88 return nullptr;
89
90 return *windowItByWId;
91}
92
94 const QSize &windowSnapshotSize, const QRect &windowSpaceCaptureRect)
95{
96 return {
97 windowSpaceCaptureRect.width() < 0
98 ? qMax(0, windowSnapshotSize.width() - windowSpaceCaptureRect.x())
99 : windowSpaceCaptureRect.width(),
100 windowSpaceCaptureRect.height() < 0
101 ? qMax(0, windowSnapshotSize.height() - windowSpaceCaptureRect.y())
102 : windowSpaceCaptureRect.height()
103 };
104}
105
107 const QRect &windowSpaceCaptureRect, const QRect &windowFragmentRect)
108{
109 return {
110 qAbs(windowSpaceCaptureRect.x() - windowFragmentRect.x()),
111 qAbs(windowSpaceCaptureRect.y() - windowFragmentRect.y()),
112 windowFragmentRect.width(),
113 windowFragmentRect.height()
114 };
115}
116
118 const QOhosPlatformScreen *platformScreen, const QPixmap &capturedWindowPixmap,
119 const QRect &windowSpaceCaptureRect)
120{
121 auto resultSize = calculateResultWindowCapturePixmapSize(
122 QHighDpi::fromNativePixels(capturedWindowPixmap.size(), platformScreen),
123 windowSpaceCaptureRect);
124
125 if (resultSize.isEmpty())
126 return {};
127
128 auto windowFragmentRect = capturedWindowPixmap.rect().intersected(
129 QRect(windowSpaceCaptureRect.topLeft(), resultSize));
130
131 if (windowFragmentRect.isEmpty())
132 return QPixmap(resultSize);
133
134 auto resultSpaceWindowFragmentRect =
135 calculateResultPixmapWindowFragmentRect(windowSpaceCaptureRect, windowFragmentRect);
136
137 QPixmap result(resultSize);
138 QPainter p(&result);
139 p.drawPixmap(
140 QHighDpi::toNativePixels(resultSpaceWindowFragmentRect, platformScreen),
141 capturedWindowPixmap,
142 QHighDpi::toNativePixels(windowFragmentRect, platformScreen));
143
144 return result;
145}
146
148{
149 using JsDisplayOrientation = QOhosDisplayInfo::JsDisplayOrientation;
150
151 switch (jsDisplayOrientation) {
152 case JsDisplayOrientation::PORTRAIT:
153 return Qt::ScreenOrientation::PortraitOrientation;
154 case JsDisplayOrientation::LANDSCAPE:
155 return Qt::ScreenOrientation::LandscapeOrientation;
156 case JsDisplayOrientation::PORTRAIT_INVERTED:
157 return Qt::ScreenOrientation::InvertedPortraitOrientation;
158 case JsDisplayOrientation::LANDSCAPE_INVERTED:
159 return Qt::ScreenOrientation::InvertedLandscapeOrientation;
160 }
161
162 return {};
163}
164
165}
166
167QOhosPlatformScreen::QOhosPlatformScreen(const QOhosDisplayInfo &displayInfo, QOhosSupplier<std::vector<QOhosPlatformScreen *>> platformScreenListSupplier)
168 : QObject()
169 , QPlatformScreen()
170 , m_format(QImage::Format_ARGB32_Premultiplied)
171 , m_depth(32)
172 , m_platformCursor(new QOhosPlatformCursor())
173 , m_displayInfo(displayInfo)
174 , m_availableGeometry(getAvailableArea())
175 , m_platformScreenListSupplier(std::move(platformScreenListSupplier))
176{
177 auto __dbg = make_QCScopedDebug("QOhosPlatformScreen::QOhosPlatformScreen");
178}
179
181
182QOhosPlatformScreen *QOhosPlatformScreen::fromQScreen(QScreen *screen)
183{
184 auto *platformScreen = screen->handle();
185 if (Q_UNLIKELY(platformScreen == nullptr))
186 qOhosReportFatalErrorAndAbort("QScreen::handle() returned null");
187 return static_cast<QOhosPlatformScreen *>(platformScreen);
188}
189
190QWindow *QOhosPlatformScreen::topLevelAt(const QPoint &p) const
191{
192 for (auto *platformScreen : virtualSiblings()) {
193 auto *ohosPlatformScreen = static_cast<QOhosPlatformScreen *>(platformScreen);
194
195 auto windowIds = QOhosWindowProxy::queryWindowIdsByCoordinate(ohosPlatformScreen->m_displayInfo.id, p);
196 if (!windowIds.empty())
197 return QWindowProxyRegistry::instance().findQWindowByJsWindowIdOrNull(windowIds.front());
198 }
199
200 return nullptr;
201}
202
204{
205 return m_platformCursor.data();
206}
207
209{
210 auto geometryChanged = displayInfo.displayGeometryPixels() != m_displayInfo.displayGeometryPixels();
211 auto logicalDpiChanged = displayInfo.densityDPI != m_displayInfo.densityDPI;
212
213 QVector<QPair<QWindow *, std::optional<QRect>>> windowRectPairs;
214
215 if (logicalDpiChanged) {
216 for (auto *window : qGuiApp->allWindows()) {
217 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(window);
218 if (platformWindow == nullptr || platformWindow->screen() != this || !window->isVisible())
219 continue;
220
221 auto *ownedView = platformWindow->ownedViewOrNull();
222 if (ownedView == nullptr)
223 continue;
224
225 windowRectPairs.push_back({
226 window,
227 ownedView->viewType() == QOhosView::ViewType::EmbeddedWindow
228 ? std::optional(window->geometry())
229 : std::nullopt});
230 }
231 }
232
233 m_displayInfo = displayInfo;
234
235 if (geometryChanged)
236 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
237
238 if (logicalDpiChanged) {
239 auto ldpi = logicalDpi();
240 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(
241 screen(), ldpi.first, ldpi.second);
242
243 QWindowSystemInterface::flushWindowSystemEvents();
244
245 for (const auto &windowRectPair : windowRectPairs) {
246 auto *qWindow = windowRectPair.first;
247 auto *platformWindow = QOhosPlatformWindow::fromQWindow(qWindow);
248 if (windowRectPair.second.has_value())
249 qWindow->setGeometry(windowRectPair.second.value());
250 platformWindow->handleDpiChange();
251 }
252 }
253}
254
256{
257 qreal lDpi = m_displayInfo.densityPixels * ohosLogicalDpi;
258 return QDpi(lDpi, lDpi);
259}
260
262{
263 // densityPixels is the scaling coefficient between the virtual pixel
264 // and the physical pixels.
265 return m_displayInfo.densityPixels;
266}
267
269{
270 return m_displayInfo.refreshRate;
271}
272
277
279{
280 return
281 qAndThen(m_displayInfo.orientation, tryMapJsDisplayOrientationToQt)
282 .value_or(Qt::ScreenOrientation::PrimaryOrientation);
283}
284
286{
287 return Qt::ScreenOrientation::PrimaryOrientation;
288}
289
290QRect QOhosPlatformScreen::getAvailableArea() const
291{
292 return QtOhos::evalInJsThreadWithPromise<QRect>(
293 [&](QtOhos::JsState &jsState, QOhosTaskPromise<QRect> evalPromise) {
294
295 QNapi::Object display;
296 try {
297 display = jsState.eval<QNapi::Object>(
298 "@ohos.display.getDisplayByIdSync(*)", {m_displayInfo.id.value()});
299 } catch (const Napi::Error &error) {
300 qOhosPrintfError(
301 "%s: getDisplayByIdSync(%f) failed with error: %s",
302 Q_FUNC_INFO, m_displayInfo.id.value(), error.Message().c_str());
303 evalPromise(QRect());
304 return;
305 }
306
307 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
308 display.evalToPromiseOrRejectOnThrow("getAvailableArea()")
309 .onThen(
310 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
311 auto availableArea = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
312 thenPromise(
313 QRect(
314 availableArea.get<QNapi::Number>("left"),
315 availableArea.get<QNapi::Number>("top"),
316 availableArea.get<QNapi::Number>("width"),
317 availableArea.get<QNapi::Number>("height")));
318 })
319 .onCatch(
320 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
321 QtOhos::logJsCallbackError(cbInfo, "Error occurred in JS getAvailableArea()");
322 catchPromise(QRect());
323 });
324 },
325 Q_FUNC_INFO);
326}
327
328void QOhosPlatformScreen::releaseSurface()
329{
330}
331
333{
334 return m_displayInfo;
335}
336
338{
339 return m_displayInfo.id.value();
340}
341
343{
344 return m_displayInfo.displayGeometryPixels();
345}
346
348{
349 auto screenGeometry = geometry();
350 return !m_availableGeometry.isEmpty()
351 ? m_availableGeometry.translated(screenGeometry.topLeft())
352 : screenGeometry;
353}
354
356{
357 return m_depth;
358}
359
361{
362 return m_format;
363}
364
366{
367 return m_displayInfo.physicalSize();
368}
369
371{
372 if (rect != m_availableGeometry) {
373 m_availableGeometry = rect;
374 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
375 }
376}
377
379{
380 if (!m_displayInfo.isDisplayMainOrExtended())
381 return QPlatformScreen::virtualSiblings();
382
383 QList<QPlatformScreen *> result;
384 auto allPlatformScreens = m_platformScreenListSupplier();
385 std::copy_if(
386 allPlatformScreens.begin(), allPlatformScreens.end(),
387 std::back_inserter(result),
388 [](QOhosPlatformScreen *ohosPlatformScreen) {
389 return ohosPlatformScreen->displayInfo().isDisplayMainOrExtended();
390 });
391
392 return result;
393}
394
395QPixmap QOhosPlatformScreen::grabWindow(WId wId, int x, int y, int width, int height) const
396{
397 auto captureRect = QRect(x, y, width, height);
398
399 if (wId != 0) {
400 auto *window = tryFindWindowByWIdOrNull(wId);
401 if (window == nullptr) {
402 qOhosPrintfError(
403 "%s: Cannot find window with the given WId: %lld.", Q_FUNC_INFO, wId);
404 return {};
405 }
406 return grabWindowFromCapturedScreenPixmap(
407 this, QOhosPlatformWindow::fromQWindow(window)->makeSnapshot(), captureRect);
408 }
409
410 auto capturedScreenPixmap = QtOhos::evalInJsThreadWithPromise<QPixmap>(
411 [displayId = m_displayInfo.id](
412 QtOhos::JsState &jsState, QOhosTaskPromise<QPixmap> evalPromise) {
413 auto sharedEvalPromise = QtOhos::moveToSharedPtr(std::move(evalPromise).makeChained(Q_FUNC_INFO));
414 tryCaptureScreenPixelmapWithPermissionCheck(
415 jsState, displayId,
416 [sharedEvalPromise](
417 std::shared_ptr<::OH_PixelmapNative> optPixelMap) {
418 (*sharedEvalPromise)(
419 optPixelMap
420 ? QPixmap::fromImage(createQImageFromNativePixelMap(optPixelMap.get()))
421 : QPixmap());
422 });
423 },
424 Q_FUNC_INFO);
425
426 return capturedScreenPixmap.copy(captureRect);
427}
428
430{
431 return m_displayInfo.name;
432}
433
434QT_END_NAMESPACE
QPixmap grabWindow(WId wId, int x, int y, int width, int height) const override
This function is called when Qt needs to be able to grab the content of a window.
double displayId() const override
QWindow * topLevelAt(const QPoint &p) const override
Return the given top level window for a given position.
Qt::ScreenOrientation orientation() const override
Reimplement this function in subclass to return the current orientation of the screen,...
QRect availableGeometry() const override
Reimplement in subclass to return the pixel geometry of the available space This normally is the desk...
QSizeF physicalSize() const override
Reimplement this function in subclass to return the physical size of the screen, in millimeters.
qreal refreshRate() const override
Reimplement this function in subclass to return the vertical refresh rate of the screen,...
QImage::Format format() const override
Reimplement in subclass to return the image format which corresponds to the screen format.
Qt::ScreenOrientation nativeOrientation() const override
Reimplement this function in subclass to return the native orientation of the screen,...
const QOhosDisplayInfo & displayInfo() const
QList< QPlatformScreen * > virtualSiblings() const override
Returns a list of all the platform screens that are part of the same virtual desktop.
QString name() const override
QPlatformCursor * cursor() const override
Reimplement this function in subclass to return the cursor of the screen.
qreal pixelScalingCoefficient() const
void setAvailableGeometry(const QRect &rect)
void setDisplayInfo(const QOhosDisplayInfo &displayInfo)
QRect geometry() const override
Reimplement in subclass to return the pixel geometry of the screen.
QDpi logicalDpi() const override
Reimplement this function in subclass to return the logical horizontal and vertical dots per inch met...
int depth() const override
Reimplement in subclass to return current depth of the screen.
QDpi logicalBaseDpi() const override
Reimplement to return the base logical DPI for the platform.
void checkAppPermissionGrantedWithConsumer(QtOhos::JsState &jsState, const std::string &permissionName, QOhosConsumer< QtOhos::JsState &, bool > resultConsumer)
Combined button and popup list for selecting options.
QWindow * tryFindWindowByWIdOrNull(WId wId)
QRect calculateResultPixmapWindowFragmentRect(const QRect &windowSpaceCaptureRect, const QRect &windowFragmentRect)
std::optional< Qt::ScreenOrientation > tryMapJsDisplayOrientationToQt(QOhosDisplayInfo::JsDisplayOrientation jsDisplayOrientation)
void tryCaptureScreenPixelmapWithPermissionCheck(QtOhos::JsState &jsState, QOhosDisplayInfo::JsDisplayId displayId, QOhosConsumer< std::shared_ptr<::OH_PixelmapNative > > pixelMapOrNullConsumer)
static const int ohosLogicalDpi
std::shared_ptr<::OH_PixelmapNative > captureScreenPixelmap(QtOhos::JsState &, QOhosDisplayInfo::JsDisplayId displayId)
QSize calculateResultWindowCapturePixmapSize(const QSize &windowSnapshotSize, const QRect &windowSpaceCaptureRect)
QPixmap grabWindowFromCapturedScreenPixmap(const QOhosPlatformScreen *platformScreen, const QPixmap &capturedWindowPixmap, const QRect &windowSpaceCaptureRect)
bool isDisplayMainOrExtended() const
QtOhos::enums::ohos::display::Orientation JsDisplayOrientation