4#include <QtCore/private/qcore_ohos_p.h>
5#include <QtCore/qdebug.h>
6#include <QtCore/qdatetime.h>
8#include <qpa/qwindowsysteminterface.h>
10#include <qohosdisplayinfo.h>
17#include "render/qohosview.h"
19#include <multimedia/image_framework/image/pixelmap_native.h>
21#include <qarkui/qarkuiutils.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#include <window_manager/oh_display_manager.h>
31#include <QtGui/qguiapplication.h>
32#include <QtGui/qwindow.h>
33#include <QtCore/private/qnapi_p.h>
34#include <QtCore/private/qohoslogger_p.h>
35#include <QtGui/private/qhighdpiscaling_p.h>
36#include <QtGui/private/qwindow_p.h>
49 ::OH_PixelmapNative *pixelMapNativePtr;
51 QArkUi::callArkUiOrFailOnErrorResult(
52 Q_OHOS_NAMED_FUNC(::OH_NativeDisplayManager_CaptureScreenPixelmap),
53 static_cast<
std::uint32_t>(displayId.value()), &pixelMapNativePtr);
55 return wrapOhosNativePixelMapPtr(pixelMapNativePtr);
60 QOhosConsumer<std::shared_ptr<::OH_PixelmapNative>> pixelMapOrNullConsumer)
62 static constexpr const char *ohosCustomScreenCapturePermission =
63 "ohos.permission.CUSTOM_SCREEN_CAPTURE";
66 jsState, ohosCustomScreenCapturePermission,
67 [pixelMapOrNullConsumer = std::move(pixelMapOrNullConsumer), displayId](
68 auto &jsState,
bool permissionGranted) {
69 if (permissionGranted) {
70 pixelMapOrNullConsumer(captureScreenPixelmap(jsState, displayId));
73 "%s: %s hasn't been granted by user. Cannot grab window.", Q_FUNC_INFO,
74 ohosCustomScreenCapturePermission);
75 pixelMapOrNullConsumer(
nullptr);
82 auto allWindows = qApp->allWindows();
83 auto windowItByWId =
std::find_if(
84 std::begin(allWindows),
std::end(allWindows),
86 return w->winId() == wId;
89 if (windowItByWId == allWindows.end())
92 return *windowItByWId;
96 const QSize &windowSnapshotSize,
const QRect &windowSpaceCaptureRect)
99 windowSpaceCaptureRect.width() < 0
100 ? qMax(0, windowSnapshotSize.width() - windowSpaceCaptureRect.x())
101 : windowSpaceCaptureRect.width(),
102 windowSpaceCaptureRect.height() < 0
103 ? qMax(0, windowSnapshotSize.height() - windowSpaceCaptureRect.y())
104 : windowSpaceCaptureRect.height()
109 const QRect &windowSpaceCaptureRect,
const QRect &windowFragmentRect)
112 qAbs(windowSpaceCaptureRect.x() - windowFragmentRect.x()),
113 qAbs(windowSpaceCaptureRect.y() - windowFragmentRect.y()),
114 windowFragmentRect.width(),
115 windowFragmentRect.height()
121 const QRect &windowSpaceCaptureRect)
123 auto resultSize = calculateResultWindowCapturePixmapSize(
124 QHighDpi::fromNativePixels(capturedWindowPixmap.size(), platformScreen),
125 windowSpaceCaptureRect);
127 if (resultSize.isEmpty())
130 auto windowFragmentRect = capturedWindowPixmap.rect().intersected(
131 QRect(windowSpaceCaptureRect.topLeft(), resultSize));
133 if (windowFragmentRect.isEmpty())
134 return QPixmap(resultSize);
136 auto resultSpaceWindowFragmentRect =
137 calculateResultPixmapWindowFragmentRect(windowSpaceCaptureRect, windowFragmentRect);
139 QPixmap result(resultSize);
142 QHighDpi::toNativePixels(resultSpaceWindowFragmentRect, platformScreen),
143 capturedWindowPixmap,
144 QHighDpi::toNativePixels(windowFragmentRect, platformScreen));
153 switch (jsDisplayOrientation) {
154 case JsDisplayOrientation::PORTRAIT:
155 return Qt::ScreenOrientation::PortraitOrientation;
156 case JsDisplayOrientation::LANDSCAPE:
157 return Qt::ScreenOrientation::LandscapeOrientation;
158 case JsDisplayOrientation::PORTRAIT_INVERTED:
159 return Qt::ScreenOrientation::InvertedPortraitOrientation;
160 case JsDisplayOrientation::LANDSCAPE_INVERTED:
161 return Qt::ScreenOrientation::InvertedLandscapeOrientation;
170 switch (orientation) {
171 case Qt::ScreenOrientation::PortraitOrientation:
173 case Qt::ScreenOrientation::LandscapeOrientation:
175 case Qt::ScreenOrientation::InvertedPortraitOrientation:
177 case Qt::ScreenOrientation::InvertedLandscapeOrientation:
187 switch (nativeOrientation) {
188 case DISPLAY_MANAGER_PORTRAIT:
189 return Qt::ScreenOrientation::PortraitOrientation;
190 case DISPLAY_MANAGER_LANDSCAPE:
191 return Qt::ScreenOrientation::LandscapeOrientation;
192 case DISPLAY_MANAGER_PORTRAIT_INVERTED:
193 return Qt::ScreenOrientation::InvertedPortraitOrientation;
194 case DISPLAY_MANAGER_LANDSCAPE_INVERTED:
195 return Qt::ScreenOrientation::InvertedLandscapeOrientation;
196 case DISPLAY_MANAGER_UNKNOWN:
205 switch (((index % 4) + 4) % 4) {
207 return Qt::ScreenOrientation::PortraitOrientation;
209 return Qt::ScreenOrientation::LandscapeOrientation;
211 return Qt::ScreenOrientation::InvertedPortraitOrientation;
213 return Qt::ScreenOrientation::InvertedLandscapeOrientation;
222 , m_format(QImage::Format_ARGB32_Premultiplied)
224 , m_platformCursor(
new QOhosPlatformCursor())
225 , m_displayInfo(displayInfo)
226 , m_availableGeometry(getAvailableArea())
227 , m_platformScreenListSupplier(std::move(platformScreenListSupplier))
229 auto __dbg = make_QCScopedDebug(
"QOhosPlatformScreen::QOhosPlatformScreen");
236 auto *platformScreen = screen->handle();
237 if (Q_UNLIKELY(platformScreen ==
nullptr))
238 qOhosReportFatalErrorAndAbort(
"QScreen::handle() returned null");
244 for (
auto *platformScreen : virtualSiblings()) {
245 auto *ohosPlatformScreen =
static_cast<QOhosPlatformScreen *>(platformScreen);
247 auto windowIds = QOhosWindowProxy::queryWindowIdsByCoordinate(ohosPlatformScreen->m_displayInfo.id, p);
248 if (!windowIds.empty())
249 return QWindowProxyRegistry::instance().findQWindowByJsWindowIdOrNull(windowIds.front());
257 return m_platformCursor.data();
262 auto geometryChanged = displayInfo.displayGeometryPixels() != m_displayInfo.displayGeometryPixels();
263 auto logicalDpiChanged = displayInfo.densityDPI != m_displayInfo.densityDPI;
264 const Qt::ScreenOrientation previousOrientation = orientation();
266 QVector<QPair<QWindow *, std::optional<QRect>>> windowRectPairs;
268 if (logicalDpiChanged) {
269 for (
auto *window : qGuiApp->allWindows()) {
270 auto *platformWindow = QOhosPlatformWindow::fromQWindowOrNull(window);
271 if (platformWindow ==
nullptr || platformWindow->screen() !=
this || !window->isVisible())
274 auto *ownedView = platformWindow->ownedViewOrNull();
275 if (ownedView ==
nullptr)
278 windowRectPairs.push_back({
280 ownedView->viewType() == QOhosView::ViewType::EmbeddedWindow
281 ? std::optional(window->geometry())
286 m_displayInfo = displayInfo;
289 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
291 if (orientation() != previousOrientation)
292 QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), orientation());
294 if (logicalDpiChanged) {
295 auto ldpi = logicalDpi();
296 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(
297 screen(), ldpi.first, ldpi.second);
299 QWindowSystemInterface::flushWindowSystemEvents();
301 for (
const auto &windowRectPair : windowRectPairs) {
302 auto *qWindow = windowRectPair.first;
303 auto *platformWindow = QOhosPlatformWindow::fromQWindow(qWindow);
304 if (windowRectPair.second.has_value())
305 qWindow->setGeometry(windowRectPair.second.value());
306 platformWindow->handleDpiChange();
313 qreal lDpi = m_displayInfo.densityPixels * ohosLogicalDpi;
314 return QDpi(lDpi, lDpi);
321 return m_displayInfo.densityPixels;
326 return m_displayInfo.refreshRate;
337 qAndThen(m_displayInfo.orientation, tryMapJsDisplayOrientationToQt)
338 .value_or(Qt::ScreenOrientation::PrimaryOrientation);
345 if (m_nativeOrientation)
346 return *m_nativeOrientation;
348 NativeDisplayManager_DisplayInfo *displayInfo =
nullptr;
349 const auto displayId =
static_cast<uint32_t>(m_displayInfo.id.value());
350 if (OH_NativeDisplayManager_CreateDisplayById(displayId, &displayInfo) != DISPLAY_MANAGER_OK
351 || displayInfo ==
nullptr) {
352 return Qt::ScreenOrientation::PrimaryOrientation;
355 const NativeDisplayManager_Orientation nativeOrientation = displayInfo->orientation;
356 const NativeDisplayManager_Rotation rotation = displayInfo->rotation;
357 OH_NativeDisplayManager_DestroyDisplay(displayInfo);
359 const auto current = tryMapNativeDisplayOrientationToQt(nativeOrientation);
361 return Qt::ScreenOrientation::PrimaryOrientation;
363 const int currentIndex = orientationToIndex(*current);
364 if (currentIndex < 0)
365 return Qt::ScreenOrientation::PrimaryOrientation;
367 m_nativeOrientation = orientationFromIndex(currentIndex -
static_cast<
int>(rotation));
368 return *m_nativeOrientation;
373 return QOhosJsThreadGateway::evalWithPromise<QRect>(
374 [&](QOhosJsState &jsState, QOhosTaskPromise<QRect> evalPromise) {
376 QNapi::Object display;
378 display = jsState.eval<QNapi::Object>(
379 "@ohos.display.getDisplayByIdSync(*)", {m_displayInfo.id.value()});
380 }
catch (
const Napi::Error &error) {
382 "%s: getDisplayByIdSync(%f) failed with error: %s",
383 Q_FUNC_INFO, m_displayInfo.id.value(), error.Message().c_str());
384 evalPromise(QRect());
388 auto thenCatchPromises = std::move(evalPromise).makeThenCatchBranches(Q_FUNC_INFO);
389 display.evalToPromiseOrRejectOnThrow(
"getAvailableArea()")
391 [thenPromise = std::move(thenCatchPromises.first)](
const QOhosCallbackInfo &cbInfo) {
392 auto availableArea = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
395 availableArea.get<QNapi::Number>(
"left"),
396 availableArea.get<QNapi::Number>(
"top"),
397 availableArea.get<QNapi::Number>(
"width"),
398 availableArea.get<QNapi::Number>(
"height")));
401 [catchPromise = std::move(thenCatchPromises.second)](
const QOhosCallbackInfo &cbInfo) {
402 QtOhos::logJsCallbackError(cbInfo,
"Error occurred in JS getAvailableArea()");
403 catchPromise(QRect());
415 return m_displayInfo;
420 return m_displayInfo.id.value();
425 return m_displayInfo.displayGeometryPixels();
430 auto screenGeometry = geometry();
431 return !m_availableGeometry.isEmpty()
432 ? m_availableGeometry.translated(screenGeometry.topLeft())
448 return m_displayInfo.physicalSize();
453 if (rect != m_availableGeometry) {
454 m_availableGeometry = rect;
455 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
461 if (!m_displayInfo.isDisplayMainOrExtended())
462 return QPlatformScreen::virtualSiblings();
464 QList<QPlatformScreen *> result;
465 auto allPlatformScreens = m_platformScreenListSupplier();
467 allPlatformScreens.begin(), allPlatformScreens.end(),
468 std::back_inserter(result),
478 auto captureRect = QRect(x, y, width, height);
481 auto *window = tryFindWindowByWIdOrNull(wId);
482 if (window ==
nullptr) {
484 "%s: Cannot find window with the given WId: %lld.", Q_FUNC_INFO, wId);
487 return grabWindowFromCapturedScreenPixmap(
488 this, QOhosPlatformWindow::fromQWindow(window)->makeSnapshot(), captureRect);
491 auto capturedScreenPixmap = QOhosJsThreadGateway::evalWithPromise<QPixmap>(
492 [displayId = m_displayInfo.id](
493 QOhosJsState &jsState, QOhosTaskPromise<QPixmap> evalPromise) {
494 auto sharedEvalPromise = QtOhos::moveToSharedPtr(std::move(evalPromise).makeChained(Q_FUNC_INFO));
495 tryCaptureScreenPixelmapWithPermissionCheck(
498 std::shared_ptr<::OH_PixelmapNative> optPixelMap) {
499 (*sharedEvalPromise)(
501 ? QPixmap::fromImage(createQImageFromNativePixelMap(optPixelMap.get()))
507 return capturedScreenPixmap.copy(captureRect);
512 return m_displayInfo.name;
void checkAppPermissionGrantedWithConsumer(QOhosJsState &jsState, const std::string &permissionName, QOhosConsumer< QOhosJsState &, 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)
std::shared_ptr<::OH_PixelmapNative > captureScreenPixelmap(QOhosJsState &, QOhosDisplayInfo::JsDisplayId displayId)
static const int ohosLogicalDpi
void tryCaptureScreenPixelmapWithPermissionCheck(QOhosJsState &jsState, QOhosDisplayInfo::JsDisplayId displayId, QOhosConsumer< std::shared_ptr<::OH_PixelmapNative > > pixelMapOrNullConsumer)
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
QtOhosQpa::enums::ohos::display::Orientation JsDisplayOrientation