4#include <QtCore/qdebug.h>
5#include <QtCore/qdatetime.h>
7#include <qpa/qwindowsysteminterface.h>
9#include <qohosdisplayinfo.h>
16#include "render/qohosview.h"
18#include <multimedia/image_framework/image/pixelmap_native.h>
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>
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>
48 ::OH_PixelmapNative *pixelMapNativePtr;
50 QArkUi::callArkUiOrFailOnErrorResult(
51 Q_OHOS_NAMED_FUNC(::OH_NativeDisplayManager_CaptureScreenPixelmap),
52 static_cast<
std::uint32_t>(displayId.value()), &pixelMapNativePtr);
54 return wrapOhosNativePixelMapPtr(pixelMapNativePtr);
59 QOhosConsumer<std::shared_ptr<::OH_PixelmapNative>> pixelMapOrNullConsumer)
61 static constexpr const char *ohosCustomScreenCapturePermission =
62 "ohos.permission.CUSTOM_SCREEN_CAPTURE";
65 jsState, ohosCustomScreenCapturePermission,
66 [pixelMapOrNullConsumer = std::move(pixelMapOrNullConsumer), displayId](
67 auto &jsState,
bool permissionGranted) {
68 if (permissionGranted) {
69 pixelMapOrNullConsumer(captureScreenPixelmap(jsState, displayId));
72 "%s: %s hasn't been granted by user. Cannot grab window.", Q_FUNC_INFO,
73 ohosCustomScreenCapturePermission);
74 pixelMapOrNullConsumer(
nullptr);
81 auto allWindows = qApp->allWindows();
82 auto windowItByWId =
std::find_if(
83 std::begin(allWindows),
std::end(allWindows),
85 return w->winId() == wId;
88 if (windowItByWId == allWindows.end())
91 return *windowItByWId;
95 const QSize &windowSnapshotSize,
const QRect &windowSpaceCaptureRect)
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()
108 const QRect &windowSpaceCaptureRect,
const QRect &windowFragmentRect)
111 qAbs(windowSpaceCaptureRect.x() - windowFragmentRect.x()),
112 qAbs(windowSpaceCaptureRect.y() - windowFragmentRect.y()),
113 windowFragmentRect.width(),
114 windowFragmentRect.height()
120 const QRect &windowSpaceCaptureRect)
122 auto resultSize = calculateResultWindowCapturePixmapSize(
123 QHighDpi::fromNativePixels(capturedWindowPixmap.size(), platformScreen),
124 windowSpaceCaptureRect);
126 if (resultSize.isEmpty())
129 auto windowFragmentRect = capturedWindowPixmap.rect().intersected(
130 QRect(windowSpaceCaptureRect.topLeft(), resultSize));
132 if (windowFragmentRect.isEmpty())
133 return QPixmap(resultSize);
135 auto resultSpaceWindowFragmentRect =
136 calculateResultPixmapWindowFragmentRect(windowSpaceCaptureRect, windowFragmentRect);
138 QPixmap result(resultSize);
141 QHighDpi::toNativePixels(resultSpaceWindowFragmentRect, platformScreen),
142 capturedWindowPixmap,
143 QHighDpi::toNativePixels(windowFragmentRect, platformScreen));
150 using JsDisplayOrientation = QOhosDisplayInfo::JsDisplayOrientation;
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;
169 switch (orientation) {
170 case Qt::ScreenOrientation::PortraitOrientation:
172 case Qt::ScreenOrientation::LandscapeOrientation:
174 case Qt::ScreenOrientation::InvertedPortraitOrientation:
176 case Qt::ScreenOrientation::InvertedLandscapeOrientation:
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:
204 switch (((index % 4) + 4) % 4) {
206 return Qt::ScreenOrientation::PortraitOrientation;
208 return Qt::ScreenOrientation::LandscapeOrientation;
210 return Qt::ScreenOrientation::InvertedPortraitOrientation;
212 return Qt::ScreenOrientation::InvertedLandscapeOrientation;
221 , m_format(QImage::Format_ARGB32_Premultiplied)
223 , m_platformCursor(
new QOhosPlatformCursor())
224 , m_displayInfo(displayInfo)
225 , m_availableGeometry(getAvailableArea())
226 , m_platformScreenListSupplier(std::move(platformScreenListSupplier))
228 auto __dbg = make_QCScopedDebug(
"QOhosPlatformScreen::QOhosPlatformScreen");
235 auto *platformScreen = screen->handle();
236 if (Q_UNLIKELY(platformScreen ==
nullptr))
237 qOhosReportFatalErrorAndAbort(
"QScreen::handle() returned null");
243 for (
auto *platformScreen : virtualSiblings()) {
244 auto *ohosPlatformScreen =
static_cast<QOhosPlatformScreen *>(platformScreen);
246 auto windowIds = QOhosWindowProxy::queryWindowIdsByCoordinate(ohosPlatformScreen->m_displayInfo.id, p);
247 if (!windowIds.empty())
248 return QWindowProxyRegistry::instance().findQWindowByJsWindowIdOrNull(windowIds.front());
256 return m_platformCursor.data();
261 auto geometryChanged = displayInfo.displayGeometryPixels() != m_displayInfo.displayGeometryPixels();
262 auto logicalDpiChanged = displayInfo.densityDPI != m_displayInfo.densityDPI;
263 const Qt::ScreenOrientation previousOrientation = orientation();
265 QVector<QPair<QWindow *, std::optional<QRect>>> windowRectPairs;
267 if (logicalDpiChanged) {
268 for (
auto *window : qGuiApp->allWindows()) {
269 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(window);
270 if (platformWindow ==
nullptr || platformWindow->screen() !=
this || !window->isVisible())
273 auto *ownedView = platformWindow->ownedViewOrNull();
274 if (ownedView ==
nullptr)
277 windowRectPairs.push_back({
279 ownedView->viewType() == QOhosView::ViewType::EmbeddedWindow
280 ? std::optional(window->geometry())
285 m_displayInfo = displayInfo;
288 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
290 if (orientation() != previousOrientation)
291 QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), orientation());
293 if (logicalDpiChanged) {
294 auto ldpi = logicalDpi();
295 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(
296 screen(), ldpi.first, ldpi.second);
298 QWindowSystemInterface::flushWindowSystemEvents();
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();
312 qreal lDpi = m_displayInfo.densityPixels * ohosLogicalDpi;
313 return QDpi(lDpi, lDpi);
320 return m_displayInfo.densityPixels;
325 return m_displayInfo.refreshRate;
336 qAndThen(m_displayInfo.orientation, tryMapJsDisplayOrientationToQt)
337 .value_or(Qt::ScreenOrientation::PrimaryOrientation);
344 if (m_nativeOrientation)
345 return *m_nativeOrientation;
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;
354 const NativeDisplayManager_Orientation nativeOrientation = displayInfo->orientation;
355 const NativeDisplayManager_Rotation rotation = displayInfo->rotation;
356 OH_NativeDisplayManager_DestroyDisplay(displayInfo);
358 const auto current = tryMapNativeDisplayOrientationToQt(nativeOrientation);
360 return Qt::ScreenOrientation::PrimaryOrientation;
362 const int currentIndex = orientationToIndex(*current);
363 if (currentIndex < 0)
364 return Qt::ScreenOrientation::PrimaryOrientation;
366 m_nativeOrientation = orientationFromIndex(currentIndex -
static_cast<
int>(rotation));
367 return *m_nativeOrientation;
372 return QtOhos::evalInJsThreadWithPromise<QRect>(
373 [&](QtOhos::JsState &jsState, QOhosTaskPromise<QRect> evalPromise) {
375 QNapi::Object display;
377 display = jsState.eval<QNapi::Object>(
378 "@ohos.display.getDisplayByIdSync(*)", {m_displayInfo.id.value()});
379 }
catch (
const Napi::Error &error) {
381 "%s: getDisplayByIdSync(%f) failed with error: %s",
382 Q_FUNC_INFO, m_displayInfo.id.value(), error.Message().c_str());
383 evalPromise(QRect());
387 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
388 display.evalToPromiseOrRejectOnThrow(
"getAvailableArea()")
390 [thenPromise = std::move(thenCatchPromises.first)](
const QtOhos::CallbackInfo &cbInfo) {
391 auto availableArea = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
394 availableArea.get<QNapi::Number>(
"left"),
395 availableArea.get<QNapi::Number>(
"top"),
396 availableArea.get<QNapi::Number>(
"width"),
397 availableArea.get<QNapi::Number>(
"height")));
400 [catchPromise = std::move(thenCatchPromises.second)](
const QtOhos::CallbackInfo &cbInfo) {
401 QtOhos::logJsCallbackError(cbInfo,
"Error occurred in JS getAvailableArea()");
402 catchPromise(QRect());
414 return m_displayInfo;
419 return m_displayInfo.id.value();
424 return m_displayInfo.displayGeometryPixels();
429 auto screenGeometry = geometry();
430 return !m_availableGeometry.isEmpty()
431 ? m_availableGeometry.translated(screenGeometry.topLeft())
447 return m_displayInfo.physicalSize();
452 if (rect != m_availableGeometry) {
453 m_availableGeometry = rect;
454 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
460 if (!m_displayInfo.isDisplayMainOrExtended())
461 return QPlatformScreen::virtualSiblings();
463 QList<QPlatformScreen *> result;
464 auto allPlatformScreens = m_platformScreenListSupplier();
466 allPlatformScreens.begin(), allPlatformScreens.end(),
467 std::back_inserter(result),
477 auto captureRect = QRect(x, y, width, height);
480 auto *window = tryFindWindowByWIdOrNull(wId);
481 if (window ==
nullptr) {
483 "%s: Cannot find window with the given WId: %lld.", Q_FUNC_INFO, wId);
486 return grabWindowFromCapturedScreenPixmap(
487 this, QOhosPlatformWindow::fromQWindow(window)->makeSnapshot(), captureRect);
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(
497 std::shared_ptr<::OH_PixelmapNative> optPixelMap) {
498 (*sharedEvalPromise)(
500 ? QPixmap::fromImage(createQImageFromNativePixelMap(optPixelMap.get()))
506 return capturedScreenPixmap.copy(captureRect);
511 return m_displayInfo.name;
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