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#include <window_manager/oh_display_manager.h>
29
30#include <QtGui/qguiapplication.h>
31#include <QtGui/qwindow.h>
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
148std::optional<Qt::ScreenOrientation> tryMapJsDisplayOrientationToQt(QOhosDisplayInfo::JsDisplayOrientation jsDisplayOrientation)
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// log2 index, one step per 90 degrees, as in QPlatformScreen::angleBetween().
167int orientationToIndex(Qt::ScreenOrientation orientation)
168{
169 switch (orientation) {
170 case Qt::ScreenOrientation::PortraitOrientation:
171 return 0;
172 case Qt::ScreenOrientation::LandscapeOrientation:
173 return 1;
174 case Qt::ScreenOrientation::InvertedPortraitOrientation:
175 return 2;
176 case Qt::ScreenOrientation::InvertedLandscapeOrientation:
177 return 3;
178 default:
179 return -1;
180 }
181}
182
184tryMapNativeDisplayOrientationToQt(NativeDisplayManager_Orientation nativeOrientation)
185{
186 switch (nativeOrientation) {
187 case DISPLAY_MANAGER_PORTRAIT:
188 return Qt::ScreenOrientation::PortraitOrientation;
189 case DISPLAY_MANAGER_LANDSCAPE:
190 return Qt::ScreenOrientation::LandscapeOrientation;
191 case DISPLAY_MANAGER_PORTRAIT_INVERTED:
192 return Qt::ScreenOrientation::InvertedPortraitOrientation;
193 case DISPLAY_MANAGER_LANDSCAPE_INVERTED:
194 return Qt::ScreenOrientation::InvertedLandscapeOrientation;
195 case DISPLAY_MANAGER_UNKNOWN:
196 break;
197 }
198
199 return {};
200}
201
203{
204 switch (((index % 4) + 4) % 4) {
205 case 0:
206 return Qt::ScreenOrientation::PortraitOrientation;
207 case 1:
208 return Qt::ScreenOrientation::LandscapeOrientation;
209 case 2:
210 return Qt::ScreenOrientation::InvertedPortraitOrientation;
211 default:
212 return Qt::ScreenOrientation::InvertedLandscapeOrientation;
213 }
214}
215
216}
217
218QOhosPlatformScreen::QOhosPlatformScreen(const QOhosDisplayInfo &displayInfo, QOhosSupplier<std::vector<QOhosPlatformScreen *>> platformScreenListSupplier)
219 : QObject()
220 , QPlatformScreen()
221 , m_format(QImage::Format_ARGB32_Premultiplied)
222 , m_depth(32)
223 , m_platformCursor(new QOhosPlatformCursor())
224 , m_displayInfo(displayInfo)
225 , m_availableGeometry(getAvailableArea())
226 , m_platformScreenListSupplier(std::move(platformScreenListSupplier))
227{
228 auto __dbg = make_QCScopedDebug("QOhosPlatformScreen::QOhosPlatformScreen");
229}
230
232
233QOhosPlatformScreen *QOhosPlatformScreen::fromQScreen(QScreen *screen)
234{
235 auto *platformScreen = screen->handle();
236 if (Q_UNLIKELY(platformScreen == nullptr))
237 qOhosReportFatalErrorAndAbort("QScreen::handle() returned null");
238 return static_cast<QOhosPlatformScreen *>(platformScreen);
239}
240
241QWindow *QOhosPlatformScreen::topLevelAt(const QPoint &p) const
242{
243 for (auto *platformScreen : virtualSiblings()) {
244 auto *ohosPlatformScreen = static_cast<QOhosPlatformScreen *>(platformScreen);
245
246 auto windowIds = QOhosWindowProxy::queryWindowIdsByCoordinate(ohosPlatformScreen->m_displayInfo.id, p);
247 if (!windowIds.empty())
248 return QWindowProxyRegistry::instance().findQWindowByJsWindowIdOrNull(windowIds.front());
249 }
250
251 return nullptr;
252}
253
255{
256 return m_platformCursor.data();
257}
258
260{
261 auto geometryChanged = displayInfo.displayGeometryPixels() != m_displayInfo.displayGeometryPixels();
262 auto logicalDpiChanged = displayInfo.densityDPI != m_displayInfo.densityDPI;
263 const Qt::ScreenOrientation previousOrientation = orientation();
264
265 QVector<QPair<QWindow *, std::optional<QRect>>> windowRectPairs;
266
267 if (logicalDpiChanged) {
268 for (auto *window : qGuiApp->allWindows()) {
269 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(window);
270 if (platformWindow == nullptr || platformWindow->screen() != this || !window->isVisible())
271 continue;
272
273 auto *ownedView = platformWindow->ownedViewOrNull();
274 if (ownedView == nullptr)
275 continue;
276
277 windowRectPairs.push_back({
278 window,
279 ownedView->viewType() == QOhosView::ViewType::EmbeddedWindow
280 ? std::optional(window->geometry())
281 : std::nullopt});
282 }
283 }
284
285 m_displayInfo = displayInfo;
286
287 if (geometryChanged)
288 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
289
290 if (orientation() != previousOrientation)
291 QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), orientation());
292
293 if (logicalDpiChanged) {
294 auto ldpi = logicalDpi();
295 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(
296 screen(), ldpi.first, ldpi.second);
297
298 QWindowSystemInterface::flushWindowSystemEvents();
299
300 for (const auto &windowRectPair : windowRectPairs) {
301 auto *qWindow = windowRectPair.first;
302 auto *platformWindow = QOhosPlatformWindow::fromQWindow(qWindow);
303 if (windowRectPair.second.has_value())
304 qWindow->setGeometry(windowRectPair.second.value());
305 platformWindow->handleDpiChange();
306 }
307 }
308}
309
311{
312 qreal lDpi = m_displayInfo.densityPixels * ohosLogicalDpi;
313 return QDpi(lDpi, lDpi);
314}
315
317{
318 // densityPixels is the scaling coefficient between the virtual pixel
319 // and the physical pixels.
320 return m_displayInfo.densityPixels;
321}
322
324{
325 return m_displayInfo.refreshRate;
326}
327
332
334{
335 return
336 qAndThen(m_displayInfo.orientation, tryMapJsDisplayOrientationToQt)
337 .value_or(Qt::ScreenOrientation::PrimaryOrientation);
338}
339
341{
342 // No direct query exists, so derive it from this display's orientation
343 // stepped back by its rotation. A hardware constant, so cache it.
344 if (m_nativeOrientation)
345 return *m_nativeOrientation;
346
347 NativeDisplayManager_DisplayInfo *displayInfo = nullptr;
348 const auto displayId = static_cast<uint32_t>(m_displayInfo.id.value());
349 if (OH_NativeDisplayManager_CreateDisplayById(displayId, &displayInfo) != DISPLAY_MANAGER_OK
350 || displayInfo == nullptr) {
351 return Qt::ScreenOrientation::PrimaryOrientation;
352 }
353
354 const NativeDisplayManager_Orientation nativeOrientation = displayInfo->orientation;
355 const NativeDisplayManager_Rotation rotation = displayInfo->rotation;
356 OH_NativeDisplayManager_DestroyDisplay(displayInfo);
357
358 const auto current = tryMapNativeDisplayOrientationToQt(nativeOrientation);
359 if (!current)
360 return Qt::ScreenOrientation::PrimaryOrientation;
361
362 const int currentIndex = orientationToIndex(*current);
363 if (currentIndex < 0)
364 return Qt::ScreenOrientation::PrimaryOrientation;
365
366 m_nativeOrientation = orientationFromIndex(currentIndex - static_cast<int>(rotation));
367 return *m_nativeOrientation;
368}
369
370QRect QOhosPlatformScreen::getAvailableArea() const
371{
372 return QtOhos::evalInJsThreadWithPromise<QRect>(
373 [&](QtOhos::JsState &jsState, QOhosTaskPromise<QRect> evalPromise) {
374
375 QNapi::Object display;
376 try {
377 display = jsState.eval<QNapi::Object>(
378 "@ohos.display.getDisplayByIdSync(*)", {m_displayInfo.id.value()});
379 } catch (const Napi::Error &error) {
380 qOhosPrintfError(
381 "%s: getDisplayByIdSync(%f) failed with error: %s",
382 Q_FUNC_INFO, m_displayInfo.id.value(), error.Message().c_str());
383 evalPromise(QRect());
384 return;
385 }
386
387 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
388 display.evalToPromiseOrRejectOnThrow("getAvailableArea()")
389 .onThen(
390 [thenPromise = std::move(thenCatchPromises.first)](const QtOhos::CallbackInfo &cbInfo) {
391 auto availableArea = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
392 thenPromise(
393 QRect(
394 availableArea.get<QNapi::Number>("left"),
395 availableArea.get<QNapi::Number>("top"),
396 availableArea.get<QNapi::Number>("width"),
397 availableArea.get<QNapi::Number>("height")));
398 })
399 .onCatch(
400 [catchPromise = std::move(thenCatchPromises.second)](const QtOhos::CallbackInfo &cbInfo) {
401 QtOhos::logJsCallbackError(cbInfo, "Error occurred in JS getAvailableArea()");
402 catchPromise(QRect());
403 });
404 },
405 Q_FUNC_INFO);
406}
407
408void QOhosPlatformScreen::releaseSurface()
409{
410}
411
413{
414 return m_displayInfo;
415}
416
418{
419 return m_displayInfo.id.value();
420}
421
423{
424 return m_displayInfo.displayGeometryPixels();
425}
426
428{
429 auto screenGeometry = geometry();
430 return !m_availableGeometry.isEmpty()
431 ? m_availableGeometry.translated(screenGeometry.topLeft())
432 : screenGeometry;
433}
434
436{
437 return m_depth;
438}
439
441{
442 return m_format;
443}
444
446{
447 return m_displayInfo.physicalSize();
448}
449
451{
452 if (rect != m_availableGeometry) {
453 m_availableGeometry = rect;
454 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
455 }
456}
457
459{
460 if (!m_displayInfo.isDisplayMainOrExtended())
461 return QPlatformScreen::virtualSiblings();
462
463 QList<QPlatformScreen *> result;
464 auto allPlatformScreens = m_platformScreenListSupplier();
465 std::copy_if(
466 allPlatformScreens.begin(), allPlatformScreens.end(),
467 std::back_inserter(result),
468 [](QOhosPlatformScreen *ohosPlatformScreen) {
469 return ohosPlatformScreen->displayInfo().isDisplayMainOrExtended();
470 });
471
472 return result;
473}
474
475QPixmap QOhosPlatformScreen::grabWindow(WId wId, int x, int y, int width, int height) const
476{
477 auto captureRect = QRect(x, y, width, height);
478
479 if (wId != 0) {
480 auto *window = tryFindWindowByWIdOrNull(wId);
481 if (window == nullptr) {
482 qOhosPrintfError(
483 "%s: Cannot find window with the given WId: %lld.", Q_FUNC_INFO, wId);
484 return {};
485 }
486 return grabWindowFromCapturedScreenPixmap(
487 this, QOhosPlatformWindow::fromQWindow(window)->makeSnapshot(), captureRect);
488 }
489
490 auto capturedScreenPixmap = QtOhos::evalInJsThreadWithPromise<QPixmap>(
491 [displayId = m_displayInfo.id](
492 QtOhos::JsState &jsState, QOhosTaskPromise<QPixmap> evalPromise) {
493 auto sharedEvalPromise = QtOhos::moveToSharedPtr(std::move(evalPromise).makeChained(Q_FUNC_INFO));
494 tryCaptureScreenPixelmapWithPermissionCheck(
495 jsState, displayId,
496 [sharedEvalPromise](
497 std::shared_ptr<::OH_PixelmapNative> optPixelMap) {
498 (*sharedEvalPromise)(
499 optPixelMap
500 ? QPixmap::fromImage(createQImageFromNativePixelMap(optPixelMap.get()))
501 : QPixmap());
502 });
503 },
504 Q_FUNC_INFO);
505
506 return capturedScreenPixmap.copy(captureRect);
507}
508
510{
511 return m_displayInfo.name;
512}
513
514QT_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.
Qt::ScreenOrientation orientationFromIndex(int index)
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)
std::optional< Qt::ScreenOrientation > tryMapNativeDisplayOrientationToQt(NativeDisplayManager_Orientation nativeOrientation)
int orientationToIndex(Qt::ScreenOrientation orientation)
QSize calculateResultWindowCapturePixmapSize(const QSize &windowSnapshotSize, const QRect &windowSpaceCaptureRect)
QPixmap grabWindowFromCapturedScreenPixmap(const QOhosPlatformScreen *platformScreen, const QPixmap &capturedWindowPixmap, const QRect &windowSpaceCaptureRect)
bool isDisplayMainOrExtended() const