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
qohosfloatingwindow.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 <qohosfloatingwindow.h>
5
6#include <QtCore/private/qohoslogger_p.h>
7#include "QtGui/private/qguiapplication_p.h"
8#include <QtGui/private/qwindow_p.h>
9#include <qohosdeviceinfo_p.h>
10#include <qohosinputcontext.h>
11#include <qohosinputmethodeventhandler.h>
12#include <qohosjsmain.h>
13#include <qohosplatformbackingstore.h>
14#include <qohosplatformintegration.h>
15#include <qohosplatformwindow.h>
16#include <qohosruntimedevicetypeandmode.h>
17#include <qohossettings.h>
18#include <render/qohossurface.h>
19#include <render/qohoswindowproxy.h>
20#include <render/qwindowproxyregistry.h>
21#include <utility>
22
24
25namespace {
26
28 QWindow *window, QOhosWindowProxy::RectChangeOptions rectChangeOptions)
29{
31 && rectChangeOptions.rect.isValid()
32 && window->geometry() != rectChangeOptions.rect
33 && rectChangeOptions.reason == QOhosWindowProxy::RectChangeReason::UNDEFINED;
34}
35
36}
37
39: QOhosPlatformWindow(window)
40{
41}
42
44
45void QOhosFloatingWindow::setGeometry(const QRect &rect)
46{
47 auto *view = ownedViewOrNull();
48 bool geometryControlledBySystem =
49 !QOhosPlatformIntegration::instance()->settings()->isWindowPcModeEnabled()
50 && view != nullptr
51 && view->viewType() == QOhosView::ViewType::MainWindow;
52
53 if (geometryControlledBySystem) {
54 setWindowGeometryFromOhos(windowGeometry());
55 return;
56 }
57
58 auto *currentScreen = QOhosPlatformWindow::screen();
59 QOhosPlatformWindow::setGeometry(rect);
60
61 auto *targetScreen = QOhosPlatformWindow::screenForGeometry(rect.marginsAdded(frameMargins()));
62 if (targetScreen != nullptr && targetScreen != currentScreen)
63 QWindowSystemInterface::handleWindowScreenChanged(window(), targetScreen->screen());
64
65 if (view != nullptr) {
66 auto frameGeometry = rect.marginsAdded(frameMargins());
67 if (!qt_window_private(window())->positionAutomatic)
68 view->setPosition(frameGeometry.topLeft());
69 view->setSize(frameGeometry.size());
70 }
71}
72
74{
75 if (!visible)
76 m_view->hide();
77 else
78 m_view->showImmediate();
79 startAsyncWaitForNodeResizeIfNeeded();
80}
81
83{
84 auto windowObjectName = window()->objectName();
85
86 qOhosPrintfDebug(
87 "%s: winId called for window named: \"%s\"",
88 Q_FUNC_INFO,
89 windowObjectName.toStdString().c_str());
90
91 return reinterpret_cast<WId>(m_view->viewWindowId());
92}
93
95{
96 auto *view = ownedViewOrNull();
97 if (view != nullptr) {
98 view->raise();
99 window()->requestUpdate();
100 }
101}
102
104{
105 auto *view = ownedViewOrNull();
106 if (view != nullptr) {
107 view->lower();
108 window()->requestUpdate();
109 }
110}
111
113{
114 auto *view = ownedViewOrNull();
115 return view != nullptr ? view->surfaceOrNull() : nullptr;
116}
117
119{
120 return m_view.get();
121}
122
124{
126 m_view = QOhosView::createForWindow(this, propertiesProvider());
127
128 auto *qWindow = window();
129
130 // HACK
131 // There is no functionality to fetch the initial window status from ohos
132 // We can only listen for the changes - we need to assume sane default for tablets
133 // so assign the default most-likely status of the tablet here.
134 if (m_view->viewType() == QOhosView::ViewType::MainWindow
135 && !QOhosPlatformIntegration::instance()->settings()->isWindowPcModeEnabled()
136 && !m_lastWindowStatusType.has_value()) {
137 m_lastWindowStatusType = QOhosWindowProxy::WindowStatusType::FULL_SCREEN;
138 }
139
140 QObject::connect(
141 m_view.get(), &QOhosView::externalContentInteractionDetected,
142 qWindow, &QOhosPlatformWindow::closeAllActivePopups);
143
144 QObject::connect(
145 m_view.get(), &QOhosView::nodeAreaChanged, m_view.get(),
146 [this](QArkUi::QQtEmbeddedWindowNode::NodeAreaInfo event) {
147 handleNodeResizeEvent(event);
148 });
149
150 QObject::connect(
151 m_view.get(), &QOhosView::windowEvent,
152 qWindow,
153 [this](QOhosWindowProxy::WindowEvent evt) { handleWindowEvent(evt); });
154
155 QObject::connect(
156 m_view.get(), &QOhosView::windowStatusChange,
157 qWindow,
158 [this](QOhosWindowProxy::WindowStatus evt) { handleWindowStatusChange(evt); });
159
160 QObject::connect(
161 m_view.get(), &QOhosView::windowVisibilityChange,
162 qWindow,
163 [this](bool visible) { handleWindowVisibilityChange(visible); });
164
165 bool monitorAvoidAreaChange =
166 !(isHandheldDeviceType() && m_view->viewType() == QOhosView::ViewType::SubWindow);
167
168 if (monitorAvoidAreaChange) {
169 QObject::connect(
170 m_view.get(), &QOhosView::avoidAreaChanged,
171 qWindow,
172 [this](QOhosWindowProxy::AvoidAreaType avoidAreaType,
173 const QOhosWindowProxy::AvoidArea &systemAvoidArea) {
174 handleAvoidAreaChanged(avoidAreaType, systemAvoidArea);
175 });
176 }
177
178 QObject::connect(
179 m_view.get(), &QOhosView::windowRectChangedInGlobalDisplay,
180 qWindow,
181 [this](const QOhosWindowProxy::RectChangeOptions &rectChangeOptions) {
182 handleWindowRectChanged(rectChangeOptions);
183 });
184
185 QObject::connect(qWindow, &QWindow::modalityChanged, m_view.get(), &QOhosView::setModality);
186
187 QObject::connect(
188 m_view.get(), &QOhosView::surfaceStatusChanged,
189 qWindow,
190 [this](const QOhosOptional<QSize> &optSurfaceSize) { handleSurfaceStatusChanged(optSurfaceSize); });
191
192 QObject::connect(qWindow, &QWindow::windowTitleChanged, m_view.get(), &QOhosView::setTitle);
193
194 QObject::connect(
195 m_view.get(), &QOhosView::windowDisplayIdChanged,
196 qWindow,
197 [this](QOhosDisplayInfo::JsDisplayId displayId) { handleWindowDisplayIdChanged(displayId); });
198}
199
200void QOhosFloatingWindow::restoreWindowCurrentCursorIfNeeded()
201{
202 auto *view = ownedViewOrNull();
203 if (view != nullptr && m_cursor.has_value())
204 view->setCursor(m_cursor.value());
205}
206
208 Qt::WindowFlags previousWindowFlags, Qt::WindowFlags currentWindowFlags)
209{
210 auto *view = ownedViewOrNull();
211 if (view == nullptr)
212 return;
213
214 view->handleWindowFlagsChange(previousWindowFlags, currentWindowFlags);
215}
216
218 Qt::WindowStates oldWindowState, Qt::WindowStates currentWindowState)
219{
220 auto *view = ownedViewOrNull();
221 if (view == nullptr)
222 return;
223
224 view->handleWindowStateChange(oldWindowState, currentWindowState);
225}
226
227void QOhosFloatingWindow::internalHijackSystemFocusAsPopup()
228{
229 QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::PopupFocusReason);
230}
231
232void QOhosFloatingWindow::focusHijackingPopupHidden()
233{
234 auto systemFocusedWindows = QWindowProxyRegistry::instance().queryWindowsWithSystemWindowAndFocus();
235 QWindowSystemInterface::handleFocusWindowChanged(
236 !systemFocusedWindows.empty() ? systemFocusedWindows.front() : nullptr,
237 Qt::ActiveWindowFocusReason);
238}
239
240void QOhosFloatingWindow::setMask(const QRegion &region)
241{
242 m_windowMask = region;
243
244 auto *view = ownedViewOrNull();
245 if (view == nullptr)
246 return;
247
248 view->setWindowMask(QOhosWindowProxy::WindowMask{region});
249}
250
252{
253 auto *view = ownedViewOrNull();
254 if (view != nullptr)
255 return view->startMoving();
256 return false;
257}
258
260{
261 if (windowFlags().testFlag(Qt::WindowDoesNotAcceptFocus) && window()->type() == Qt::Popup) {
262 internalHijackSystemFocusAsPopup();
263 return;
264 }
265
267}
268
269void QOhosFloatingWindow::handleWindowEvent(QOhosWindowProxy::WindowEvent evt)
270{
271 auto *qWindow = window();
272 bool windowAcceptsFocusAndInput = checkWindowAcceptsFocus() && checkWindowAcceptsInput();
273 Qt::WindowStates windowStatesToSet = windowStates();
274 bool windowActive = true;
275 auto previousWindowEventType = std::exchange(m_lastWindowEventType, makeQOhosOptional(evt.type));
276
277 switch (evt.type) {
278 case QOhosWindowProxy::WindowEventType::WINDOW_ACTIVE:
279 {
280 QWindow *modalWindow = nullptr;
281 if (QGuiApplicationPrivate::instance()->isWindowBlocked(qWindow, &modalWindow)
282 && qWindow != modalWindow) {
283 modalWindow->requestActivate();
284 return;
285 }
286
287 // FIXME - restore cursor set by the User every time window is activated.
288 // Perform it because Ohos overrides it with default "standard arrow" cursor (when
289 // window is deactivated) and does not bring selected cursor back (when window is
290 // activated again). This bahaviour is Ohos platform issue.
291 restoreWindowCurrentCursorIfNeeded();
292 if (windowAcceptsFocusAndInput) {
293 QWindowSystemInterface::handleFocusWindowChanged(qWindow, Qt::ActiveWindowFocusReason);
295 }
296 break;
297 }
298 case QOhosWindowProxy::WindowEventType::WINDOW_INACTIVE:
299 windowActive = false;
300 if (!windowAcceptsFocusAndInput)
301 break;
302 if (QGuiApplicationPrivate::focus_window == qWindow
303 || (QGuiApplicationPrivate::focus_window != nullptr
304 && QOhosPlatformWindow::platformWindowFlagsForQWindow(
305 QGuiApplicationPrivate::focus_window).testFlag(Qt::WindowDoesNotAcceptFocus))) {
306 QWindowSystemInterface::handleFocusWindowChanged(nullptr, Qt::ActiveWindowFocusReason);
307 }
309 break;
310 case QOhosWindowProxy::WindowEventType::WINDOW_HIDDEN:
311 if (!checkWindowAcceptsFocus() && QGuiApplicationPrivate::focus_window == qWindow)
312 focusHijackingPopupHidden();
313 setExposedFromOhos(false);
314 windowActive = false;
315 break;
316 case QOhosWindowProxy::WindowEventType::WINDOW_SHOWN:
317 // HACK
318 // This is a fix for the windows hidden using `QWidget::hide()`.
319 // When a window is hidden and then bring back from the system Dock
320 // Qt side keeps wrong (hidden) state. This causes different issues due to
321 // improper state. To fix it - change visibility state based on the system
322 // window state.
323 if (previousWindowEventType == QOhosWindowProxy::WindowEventType::WINDOW_HIDDEN && !qWindow->isVisible())
324 qWindow->setVisible(true);
325 setExposedFromOhos(true);
326 startAsyncWaitForNodeResizeIfNeeded();
327 break;
328 case QOhosWindowProxy::WindowEventType::WINDOW_DESTROYED:
329 windowActive = false;
331 return;
332 }
333
334 windowStatesToSet.setFlag(Qt::WindowState::WindowActive, windowActive && windowAcceptsFocusAndInput);
335 setWindowStateFromOhos(windowStatesToSet);
336}
337
338void QOhosFloatingWindow::handleWindowStatusChange(QOhosWindowProxy::WindowStatus evt)
339{
340 auto *qWindow = window();
341 qCDebug(
342 QtForOhos,
343 "Window status changed, window: %p(%s) status: %d",
344 qWindow,
345 qPrintable(qWindow->objectName()),
346 evt.type);
347 Qt::WindowStates windowStatesToSet = windowStates();
348 Qt::WindowState flagToSet;
349 m_lastWindowStatusType = evt.type;
350
351 switch (evt.type) {
352 case QOhosWindowProxy::WindowStatusType::FULL_SCREEN:
353 flagToSet = Qt::WindowState::WindowFullScreen;
354 break;
355 case QOhosWindowProxy::WindowStatusType::MAXIMIZE:
356 flagToSet = Qt::WindowState::WindowMaximized;
357 break;
358 case QOhosWindowProxy::WindowStatusType::MINIMIZE:
359 flagToSet = Qt::WindowState::WindowMinimized;
360 break;
361 case QOhosWindowProxy::WindowStatusType::UNDEFINED:
362 case QOhosWindowProxy::WindowStatusType::FLOATING:
363 Q_FALLTHROUGH();
364 case QOhosWindowProxy::WindowStatusType::SPLIT_SCREEN:
365 flagToSet = Qt::WindowState::WindowNoState;
366 break;
367 }
368
369 // NOTE - Qt::WindowFullScreen and Qt::WindowMaximized represent the exact same
370 // OHOS Window state.
371 if (flagToSet == Qt::WindowState::WindowFullScreen
372 || flagToSet == Qt::WindowState::WindowMaximized) {
373 windowStatesToSet = m_view->isFullscreenImmersiveModeEnabled()
374 ? Qt::WindowState::WindowFullScreen
375 : Qt::WindowState::WindowMaximized;
376 } else {
377 static constexpr Qt::WindowState mutuallyExclusiveFlags[] = {
378 Qt::WindowState::WindowFullScreen,
379 Qt::WindowState::WindowMaximized,
380 Qt::WindowState::WindowMinimized,
381 Qt::WindowState::WindowNoState,
382 };
383
384 for (const auto exclusiveState : mutuallyExclusiveFlags)
385 windowStatesToSet.setFlag(exclusiveState, flagToSet == exclusiveState);
386 }
387
388 setWindowStateFromOhos(windowStatesToSet);
389
390 // HACK
391 // There is no functionality in OHOS to fetch the window status that would allow checking
392 // the value while processing the WINDOW_SHOWN window event type. Therefore, the window
393 // geometry view needs to be recalculated with any change.
394 startAsyncWaitForNodeResizeIfNeeded();
395}
396
397void QOhosFloatingWindow::handleWindowVisibilityChange(bool visible)
398{
399 auto *qWindow = window();
400 qCDebug(
401 QtForOhos,
402 "Window %p(%s) visibility changed: %s",
403 qWindow,
404 qPrintable(qWindow->objectName()),
405 visible ? "true" : "false");
406 if (visible && m_windowMask.has_value())
407 m_view->setWindowMask(QOhosWindowProxy::WindowMask{m_windowMask.value()});
408
409 setExposedFromOhos(visible);
410}
411
412void QOhosFloatingWindow::handleAvoidAreaChanged(
413 QOhosWindowProxy::AvoidAreaType avoidAreaType,
414 const QOhosWindowProxy::AvoidArea &systemAvoidArea)
415{
416 const auto &cached = m_avoidAreaCache[avoidAreaType];
417
418 bool actuallyChanged =
419 cached.visible != systemAvoidArea.visible
420 || cached.leftRect != systemAvoidArea.leftRect
421 || cached.rightRect != systemAvoidArea.rightRect
422 || cached.bottomRect != systemAvoidArea.bottomRect
423 || cached.topRect != systemAvoidArea.topRect;
424
425 if (actuallyChanged) {
426 m_avoidAreaCache[avoidAreaType] = systemAvoidArea;
427 qCDebug(QtForOhos) << "Avoid area changed:"
428 << static_cast<int>(avoidAreaType)
429 << "visible:" << systemAvoidArea.visible
430 << "top:" << systemAvoidArea.topRect
431 << "left:" << systemAvoidArea.leftRect
432 << "right:" << systemAvoidArea.rightRect
433 << "bottom:" << systemAvoidArea.bottomRect;
434 startAsyncWaitForNodeResizeIfNeeded();
435 }
436}
437
438void QOhosFloatingWindow::handleSurfaceStatusChanged(const QOhosOptional<QSize> &optSurfaceSize)
439{
440 m_optLastSurfaceSize = optSurfaceSize;
441 bool hasSurface = m_view->surfaceOrNull() != nullptr;
442 if (m_view->viewType() == QOhosView::ViewType::EmbeddedWindow) {
443 setExposedFromOhos(hasSurface);
444 }
445
446 if (hasSurface)
447 startAsyncWaitForNodeResizeIfNeeded();
448}
449
450void QOhosFloatingWindow::handleWindowDisplayIdChanged(QOhosDisplayInfo::JsDisplayId displayId)
451{
452 setDisplayIdFromOhos(makeQOhosOptional(displayId));
453 startAsyncWaitForNodeResizeIfNeeded();
454}
455
456void QOhosFloatingWindow::handleWindowRectChanged(
457 const QOhosWindowProxy::RectChangeOptions &rectChangeOptions)
458{
459 bool needsCloseAllActivePopups = rectChangeOptions.reason == QOhosWindowProxy::RectChangeReason::DRAG_START;
460
461 qCDebug(QtForOhos)
462 << "windowRectChanged window:" << window()
463 << "rect:" << rectChangeOptions.rect
464 << "reason:" << static_cast<int>(rectChangeOptions.reason);
465
466 startAsyncWaitForNodeResizeIfNeeded();
467
468 if (isWindowRotatedByTabletScreenRotation(window(), rectChangeOptions))
469 needsCloseAllActivePopups = true;
470
471 if (needsCloseAllActivePopups)
473}
474
476{
477 if (event->type() == QEvent::Timer) {
478 auto *timerEvent = static_cast<QTimerEvent *>(event);
479 if (m_view && timerEvent->timerId() == m_geometryChangeTimer.timerId()) {
480 auto syntheticEvent = m_view->nodeAreaInfo();
481 handleNodeResizeEvent(syntheticEvent);
482 }
483 }
484
485 return QOhosPlatformWindow::windowEvent(event);
486}
487
488void QOhosFloatingWindow::startAsyncWaitForNodeResizeIfNeeded()
489{
490 constexpr auto geometryChangeEventTimeoutMs = std::chrono::milliseconds(16);
491
492 if (!m_geometryChangeTimer.isActive()) {
493 m_geometryChangeTimer.start(
494 geometryChangeEventTimeoutMs.count(),
495 Qt::PreciseTimer,
496 window());
497 }
498}
499
500void QOhosFloatingWindow::handleNodeResizeEvent(const QArkUi::QQtEmbeddedWindowNode::NodeAreaInfo &areaChangeEvent)
501{
502 m_geometryChangeTimer.stop();
503
504 if (Q_UNLIKELY(!m_view))
505 return;
506
507 setWindowGeometryFromOhos(
508 m_view->viewType() != QOhosView::ViewType::EmbeddedWindow
509 ? QRect(areaChangeEvent.globalRelativeOffsetPixels, areaChangeEvent.screenGeometryPixels.size())
510 : QRect(areaChangeEvent.parentRelativeOffsetPixels, areaChangeEvent.screenGeometryPixels.size()));
511}
512
513QT_END_NAMESPACE
QOhosFloatingWindow(QWindow *window)
~QOhosFloatingWindow() override
void requestActivateWindow() override
Reimplement to let Qt be able to request activation/focus for a window.
void setVisible(bool visible) override
Reimplemented in subclasses to show the surface if visible is true, and hide it if visible is false.
bool startSystemMove() override
Reimplement this method to start a system move operation if the system supports it and return true to...
QOhosView * ownedViewOrNull() const override
void onWindowStateChanged(Qt::WindowStates oldWindowState, Qt::WindowStates currentWindowState) override
WId winId() const override
Reimplement in subclasses to return a handle to the native window.
void initialize() override
Called as part of QWindow::create(), after constructing the window.
void onWindowFlagsChanged(Qt::WindowFlags previousWindowFlags, Qt::WindowFlags currentWindowFlags) override
bool windowEvent(QEvent *event) override
Reimplement this method to be able to do any platform specific event handling.
void setGeometry(const QRect &rect) override
This function is called by Qt whenever a window is moved or resized using the QWindow API.
QOhosSurface * ownedSurfaceOrNull() const override
void setMask(const QRegion &region) override
Reimplement to be able to let Qt set the mask of a window.
void lower() override
Reimplement to be able to let Qt lower windows to the bottom of the desktop.
void raise() override
Reimplement to be able to let Qt raise windows to the top of the desktop.
static QOhosPlatformIntegration * instance()
void setExposedFromOhos(bool exposed)
void initialize() override
Called as part of QWindow::create(), after constructing the window.
void notifyInputSystemsWindowActiveStatusChanged(bool active)
void requestActivateWindow() override
Reimplement to let Qt be able to request activation/focus for a window.
bool isWindowPcModeEnabled() const
QOhosSurface * surfaceOrNull() const
void setWindowMask(const QOhosWindowProxy::WindowMask &windowMask)
void lower()
bool startMoving()
void raise()
QtOhos::enums::ohos::window::AvoidAreaType AvoidAreaType
QtOhos::enums::ohos::window::RectChangeReason RectChangeReason
QtOhos::enums::ohos::window::WindowEventType WindowEventType
QtOhos::enums::ohos::window::WindowStatusType WindowStatusType
static QWindowProxyRegistry & instance()
Combined button and popup list for selecting options.
bool isWindowRotatedByTabletScreenRotation(QWindow *window, QOhosWindowProxy::RectChangeOptions rectChangeOptions)