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