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 <QDebug>
5#include <QTime>
6
7#include <qpa/qwindowsysteminterface.h>
8
9#include <qohosdisplayinfo.h>
14#include "qohosjsmain.h"
16#include "render/qohosview.h"
17#include <multimedia/image_framework/image/pixelmap_native.h>
18#include <qarkui/qarkuiutils.h>
19#include <qguiapplication.h>
20#include <qohosapppermissions_p.h>
21#include <qohosjsutils.h>
22#include <qohospixelmapconversions.h>
23#include <qohosutils.h>
24#include <render/qwindowproxyregistry.h>
25#include <window_manager/oh_display_capture.h>
26
27#include <QtGui/QGuiApplication>
28#include <QtGui/QWindow>
29#include <QtCore/private/qnapi_p.h>
30#include <QtCore/private/qohoslogger_p.h>
31#include <QtGui/private/qhighdpiscaling_p.h>
32#include <QtGui/private/qwindow_p.h>
33
34#include <vector>
35
37
38namespace {
39
40static const int ohosLogicalDpi = 72;
41
43 QtOhos::JsState &, QOhosDisplayInfo::JsDisplayId displayId)
44{
45 ::OH_PixelmapNative *pixelMapNativePtr;
46
47 QArkUi::callArkUiOrFailOnErrorResult(
48 Q_OHOS_NAMED_FUNC(::OH_NativeDisplayManager_CaptureScreenPixelmap),
49 static_cast<std::uint32_t>(displayId.value()), &pixelMapNativePtr);
50
51 return wrapNativePixelMapPtr(pixelMapNativePtr);
52}
53
55 QtOhos::JsState &jsState, QOhosDisplayInfo::JsDisplayId displayId,
56 QOhosConsumer<std::shared_ptr<::OH_PixelmapNative>> pixelMapOrNullConsumer)
57{
58 static constexpr const char *ohosCustomScreenCapturePermission =
59 "ohos.permission.CUSTOM_SCREEN_CAPTURE";
60
62 jsState, ohosCustomScreenCapturePermission,
63 [pixelMapOrNullConsumer = std::move(pixelMapOrNullConsumer), displayId](
64 auto &jsState, bool permissionGranted) {
65 if (permissionGranted) {
66 pixelMapOrNullConsumer(captureScreenPixelmap(jsState, displayId));
67 } else {
68 qOhosPrintfError(
69 "%s: %s hasn't been granted by user. Cannot grab window.", Q_FUNC_INFO,
70 ohosCustomScreenCapturePermission);
71 pixelMapOrNullConsumer(nullptr);
72 }
73 });
74}
75
77{
78 auto allWindows = qApp->allWindows();
79 auto windowItByWId = std::find_if(
80 std::begin(allWindows), std::end(allWindows),
81 [&](QWindow *w) {
82 return w->winId() == wId;
83 });
84
85 if (windowItByWId == allWindows.end())
86 return nullptr;
87
88 return *windowItByWId;
89}
90
92 const QSize &windowSnapshotSize, const QRect &windowSpaceCaptureRect)
93{
94 return {
95 windowSpaceCaptureRect.width() < 0
96 ? qMax(0, windowSnapshotSize.width() - windowSpaceCaptureRect.x())
97 : windowSpaceCaptureRect.width(),
98 windowSpaceCaptureRect.height() < 0
99 ? qMax(0, windowSnapshotSize.height() - windowSpaceCaptureRect.y())
100 : windowSpaceCaptureRect.height()
101 };
102}
103
105 const QRect &windowSpaceCaptureRect, const QRect &windowFragmentRect)
106{
107 return {
108 qAbs(windowSpaceCaptureRect.x() - windowFragmentRect.x()),
109 qAbs(windowSpaceCaptureRect.y() - windowFragmentRect.y()),
110 windowFragmentRect.width(),
111 windowFragmentRect.height()
112 };
113}
114
116 const QOhosPlatformScreen *platformScreen, const QPixmap &capturedWindowPixmap,
117 const QRect &windowSpaceCaptureRect)
118{
119 auto resultSize = calculateResultWindowCapturePixmapSize(
120 QHighDpi::fromNativePixels(capturedWindowPixmap.size(), platformScreen),
121 windowSpaceCaptureRect);
122
123 if (resultSize.isEmpty())
124 return {};
125
126 auto windowFragmentRect = capturedWindowPixmap.rect().intersected(
127 QRect(windowSpaceCaptureRect.topLeft(), resultSize));
128
129 if (windowFragmentRect.isEmpty())
130 return QPixmap(resultSize);
131
132 auto resultSpaceWindowFragmentRect =
133 calculateResultPixmapWindowFragmentRect(windowSpaceCaptureRect, windowFragmentRect);
134
135 QPixmap result(resultSize);
136 QPainter p(&result);
137 p.drawPixmap(
138 QHighDpi::toNativePixels(resultSpaceWindowFragmentRect, platformScreen),
139 capturedWindowPixmap,
140 QHighDpi::toNativePixels(windowFragmentRect, platformScreen));
141
142 return result;
143}
144
146{
147 using JsDisplayOrientation = QOhosDisplayInfo::JsDisplayOrientation;
148
149 switch (jsDisplayOrientation) {
150 case JsDisplayOrientation::PORTRAIT:
151 return makeQOhosOptional(Qt::ScreenOrientation::PortraitOrientation);
152 case JsDisplayOrientation::LANDSCAPE:
153 return makeQOhosOptional(Qt::ScreenOrientation::LandscapeOrientation);
154 case JsDisplayOrientation::PORTRAIT_INVERTED:
155 return makeQOhosOptional(Qt::ScreenOrientation::InvertedPortraitOrientation);
156 case JsDisplayOrientation::LANDSCAPE_INVERTED:
157 return makeQOhosOptional(Qt::ScreenOrientation::InvertedLandscapeOrientation);
158 }
159
160 return {};
161}
162
163}
164
165QOhosPlatformScreen::QOhosPlatformScreen(const QOhosDisplayInfo &displayInfo)
166 : QObject()
167 , QPlatformScreen()
168 , m_format(QImage::Format_ARGB32_Premultiplied)
169 , m_depth(32)
170 , m_platformCursor(new QOhosPlatformCursor())
171 , m_displayInfo(displayInfo)
172 , m_availableGeometry(getAvailableArea())
173{
174 auto __dbg = make_QCScopedDebug("QOhosPlatformScreen::QOhosPlatformScreen");
175}
176
178
179QOhosPlatformScreen *QOhosPlatformScreen::fromQScreen(QScreen *screen)
180{
181 auto *platformScreen = screen->handle();
182 if (Q_UNLIKELY(platformScreen == nullptr))
183 qOhosReportFatalErrorAndAbort("QScreen::handle() returned null");
184 return static_cast<QOhosPlatformScreen *>(platformScreen);
185}
186
187QWindow *QOhosPlatformScreen::topLevelAt(const QPoint &p) const
188{
189 auto windowIds = QOhosWindowProxy::queryWindowIdsByCoordinate(m_displayInfo.id, p);
190 return !windowIds.empty()
191 ? QWindowProxyRegistry::instance().findQWindowByJsWindowIdOrNull(windowIds.front())
192 : nullptr;
193}
194
196{
197 return m_platformCursor.data();
198}
199
201{
202 auto geometryChanged = displayInfo.displayGeometryPixels() != m_displayInfo.displayGeometryPixels();
203 auto logicalDpiChanged = displayInfo.densityDPI != m_displayInfo.densityDPI;
204
205 QVector<QPair<QWindow *, QOhosOptional<QRect>>> windowRectPairs;
206
207 if (logicalDpiChanged) {
208 for (auto *window : qGuiApp->allWindows()) {
209 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(window);
210 if (platformWindow == nullptr || platformWindow->screen() != this || !window->isVisible())
211 continue;
212
213 auto *ownedView = platformWindow->ownedViewOrNull();
214 if (ownedView == nullptr)
215 continue;
216
217 windowRectPairs.push_back({
218 window,
219 ownedView->viewType() == QOhosView::ViewType::EmbeddedWindow
220 ? makeQOhosOptional(window->geometry())
221 : makeEmptyQOhosOptional()});
222 }
223 }
224
225 m_displayInfo = displayInfo;
226
227 if (geometryChanged)
228 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
229
230 if (logicalDpiChanged) {
231 auto ldpi = logicalDpi();
232 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(
233 screen(), ldpi.first, ldpi.second);
234
235 QWindowSystemInterface::flushWindowSystemEvents();
236
237 for (const auto &windowRectPair : windowRectPairs) {
238 auto *qWindow = windowRectPair.first;
239 auto *platformWindow = QOhosPlatformWindow::fromQWindow(qWindow);
240 if (windowRectPair.second.hasValue())
241 qWindow->setGeometry(windowRectPair.second.value());
242 platformWindow->handleDpiChange();
243 }
244 }
245}
246
248{
249 qreal lDpi = m_displayInfo.densityPixels * ohosLogicalDpi;
250 return QDpi(lDpi, lDpi);
251}
252
254{
255 // densityPixels is the scaling coefficient between the virtual pixel
256 // and the physical pixels.
257 return m_displayInfo.densityPixels;
258}
259
264
266{
267 return
268 m_displayInfo.orientation
269 .andThen(tryMapJsDisplayOrientationToQt)
270 .valueOr(Qt::ScreenOrientation::PrimaryOrientation);
271}
272
274{
275 return Qt::ScreenOrientation::PrimaryOrientation;
276}
277
278QRect QOhosPlatformScreen::getAvailableArea() const
279{
280 return QtOhos::evalInJsThreadWithConsumer<QRect>(
281 [&](QtOhos::JsState &jsState, QOhosConsumer<QRect> resultConsumer) {
282
283 QNapi::Object display;
284 try {
285 display = jsState.eval<QNapi::Object>(
286 "@ohos.display.getDisplayByIdSync(*)", {m_displayInfo.id.value()});
287 } catch (const Napi::Error &error) {
288 qOhosPrintfError(
289 "%s: getDisplayByIdSync(%f) failed with error: %s",
290 Q_FUNC_INFO, m_displayInfo.id.value(), error.Message().c_str());
291 resultConsumer(QRect());
292 return;
293 }
294
295 display.call<QNapi::Promise>("getAvailableArea")
296 .withContext(std::move(resultConsumer))
297 .onThenWithContext(
298 [](const QtOhos::CallbackInfo &cbInfo, QOhosConsumer<QRect> &resultConsumer) {
299 auto availableArea = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
300 resultConsumer(
301 QRect(
302 availableArea.get<QNapi::Number>("left"),
303 availableArea.get<QNapi::Number>("top"),
304 availableArea.get<QNapi::Number>("width"),
305 availableArea.get<QNapi::Number>("height")));
306 })
307 .onCatchWithContext(
308 [](const QtOhos::CallbackInfo &cbInfo, QOhosConsumer<QRect> &resultConsumer) {
309 QtOhos::logJsCallbackError(cbInfo, "Error occurred in JS getAvailableArea()");
310 resultConsumer(QRect());
311 });
312 });
313}
314
315void QOhosPlatformScreen::releaseSurface()
316{
317}
318
320{
321 return m_displayInfo;
322}
323
325{
326 return m_displayInfo.displayGeometryPixels();
327}
328
330{
331 return !m_availableGeometry.isEmpty() ? m_availableGeometry : geometry();
332}
333
335{
336 return m_depth;
337}
338
340{
341 return m_format;
342}
343
345{
346 return m_displayInfo.physicalSize();
347}
348
350{
351 if (rect != m_availableGeometry) {
352 m_availableGeometry = rect;
353 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
354 }
355}
356
357QPixmap QOhosPlatformScreen::grabWindow(WId wId, int x, int y, int width, int height) const
358{
359 auto captureRect = QRect(x, y, width, height);
360
361 if (wId != 0) {
362 auto *window = tryFindWindowByWIdOrNull(wId);
363 if (window == nullptr) {
364 qOhosPrintfError(
365 "%s: Cannot find window with the given WId: %lld.", Q_FUNC_INFO, wId);
366 return {};
367 }
368 return grabWindowFromCapturedScreenPixmap(
369 this, QOhosPlatformWindow::fromQWindow(window)->makeSnapshot(), captureRect);
370 }
371
372 auto capturedScreenPixmap = QtOhos::evalInJsThreadWithConsumer<QPixmap>(
373 [displayId = m_displayInfo.id](
374 QtOhos::JsState &jsState, QOhosConsumer<QPixmap> resultConsumer) {
375 tryCaptureScreenPixelmapWithPermissionCheck(
376 jsState, displayId,
377 [resultConsumer = std::move(resultConsumer)](
378 std::shared_ptr<::OH_PixelmapNative> optPixelMap) {
379 resultConsumer(
380 optPixelMap
381 ? QPixmap::fromImage(createQImageFromNativePixelMap(optPixelMap.get()))
382 : QPixmap());
383 });
384 });
385
386 return capturedScreenPixmap.copy(captureRect);
387}
388
390{
391 return m_displayInfo.name;
392}
393
394QT_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.
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.
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
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.
static QWindowProxyRegistry & instance()
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)
void tryCaptureScreenPixelmapWithPermissionCheck(QtOhos::JsState &jsState, QOhosDisplayInfo::JsDisplayId displayId, QOhosConsumer< std::shared_ptr<::OH_PixelmapNative > > pixelMapOrNullConsumer)
static const int ohosLogicalDpi
QOhosOptional< Qt::ScreenOrientation > tryMapJsDisplayOrientationToQt(QOhosDisplayInfo::JsDisplayOrientation jsDisplayOrientation)
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)
#define qApp
#define qGuiApp