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