12#include <qguiapplication.h>
13#include <qpa/qwindowsysteminterface.h>
14#include <private/qhighdpiscaling_p.h>
15#include <private/qjnihelpers_p.h>
19Q_LOGGING_CATEGORY(lcQpaWindow,
"qt.qpa.window")
21Q_DECLARE_JNI_CLASS(QtWindowInterface,
"org/qtproject/qt/android/QtWindowInterface")
22Q_DECLARE_JNI_CLASS(QtInputInterface,
"org/qtproject/qt/android/QtInputInterface")
23Q_DECLARE_JNI_CLASS(QtInputConnectionListener,
24 "org/qtproject/qt/android/QtInputConnection$QtInputConnectionListener")
25Q_DECLARE_JNI_CLASS(QtDisplayManager,
"org/qtproject/qt/android/QtWindowInterface")
26Q_DECLARE_JNI_CLASS(QtWindowInsetsController,
"org/qtproject/qt/android/QtWindowInsetsController")
28QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
29 : QPlatformWindow(window), m_nativeQtWindow(
nullptr),
30 m_surfaceContainerType(SurfaceContainer::TextureView), m_nativeParentQtWindow(
nullptr),
31 m_androidSurfaceObject(
nullptr)
33 if (window->surfaceType() == QSurface::RasterSurface)
34 window->setSurfaceType(QSurface::OpenGLSurface);
42 QWindow *window = QPlatformWindow::window();
46 if (!androidParent->isEmbeddingContainer())
47 m_nativeParentQtWindow = androidParent->nativeWindow();
51 QtJniTypes::QtInputConnectionListener listener =
52 reg->callInterface<QtJniTypes::QtInputInterface, QtJniTypes::QtInputConnectionListener>(
53 "getInputConnectionListener");
55 m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
56 QNativeInterface::QAndroidApplication::context(),
57 isForeignWindow(), m_nativeParentQtWindow, listener);
58 m_nativeViewId = m_nativeQtWindow.callMethod<jint>(
"getId");
62 m_isRaster = window->surfaceType() == QSurface::RasterSurface;
65 const bool forceMaximize = window->windowStates() & (Qt::WindowMaximized | Qt::WindowFullScreen);
66 const QRect nativeScreenGeometry = platformScreen()->availableGeometry();
68 setGeometry(nativeScreenGeometry);
70 const QRect requestedNativeGeometry = QHighDpi::toNativePixels(window->geometry(), window);
71 const QRect availableDeviceIndependentGeometry = (window->parent())
72 ? window->parent()->geometry()
73 : QHighDpi::fromNativePixels(nativeScreenGeometry, window);
75 const QRect finalNativeGeometry = QPlatformWindow::initialGeometry(
76 window, requestedNativeGeometry, availableDeviceIndependentGeometry.width(),
77 availableDeviceIndependentGeometry.height());
78 setGeometry(finalNativeGeometry);
81 if (window->isTopLevel())
82 platformScreen()->addWindow(
this);
84 static bool ok =
false;
85 static const int value = qEnvironmentVariableIntValue(
"QT_ANDROID_SURFACE_CONTAINER_TYPE", &ok);
90 }
else if (platformScreen()->windows().size() <= 1) {
96 qCDebug(lcQpaWindow) <<
"Window" <<
m_nativeViewId <<
"using surface container type"
102 const auto guard = destructionGuard();
103 if (window()->isTopLevel())
104 platformScreen()->removeWindow(
this);
110 if (m_nativeParentQtWindow.isValid()) {
111 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToBack", nativeViewId());
114 platformScreen()->lower(
this);
119 if (m_nativeParentQtWindow.isValid()) {
120 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToFront", nativeViewId());
123 updateSystemUiVisibility(window()->windowStates(), window()->flags());
124 platformScreen()->raise(
this);
129 return m_safeAreaMargins;
134 m_safeAreaMargins = safeMargins;
140 Q_ASSERT(m_nativeQtWindow.isValid());
146 if (!rect.isNull()) {
152 m_nativeQtWindow.callMethod<
void>(
"setGeometry", x, y, w, h);
155 QWindowSystemInterface::handleGeometryChange(window(), rect);
163 if (window()->isTopLevel()) {
164 if (!visible && window() ==
qGuiApp->focusWindow()) {
165 platformScreen()->topVisibleWindowChanged();
167 const Qt::WindowStates states = window()->windowStates();
168 const Qt::WindowFlags flags = window()->flags();
169 updateSystemUiVisibility(states, flags);
170 if (states & Qt::WindowFullScreen || flags & Qt::ExpandedClientAreaHint)
171 setGeometry(platformScreen()->geometry());
172 else if (states & Qt::WindowMaximized)
173 setGeometry(platformScreen()->availableGeometry());
178 m_nativeQtWindow.callMethod<
void>(
"setVisible", visible);
180 if (geometry().isEmpty() || screen()->availableGeometry().isEmpty())
183 QPlatformWindow::setVisible(visible);
188 QPlatformWindow::setWindowState(state);
190 if (window()->isVisible())
191 updateSystemUiVisibility(state, window()->flags());
196 QPlatformWindow::setWindowFlags(flags);
198 if (window()->isVisible())
199 updateSystemUiVisibility(window()->windowStates(), flags);
204 using namespace QtJniTypes;
208 if (androidWindow->isEmbeddingContainer())
211 if (!m_nativeParentQtWindow.isValid())
212 platformScreen()->removeWindow(
this);
214 const QtWindow parentWindow = androidWindow->nativeWindow();
216 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent", parentWindow.object());
217 m_nativeParentQtWindow = parentWindow;
219 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent",
nullptr);
220 m_nativeParentQtWindow = QJniObject();
221 platformScreen()->addWindow(
this);
227 return m_nativeQtWindow.isValid() ?
reinterpret_cast<WId>(m_nativeQtWindow.object()) : 0L;
246 if (m_nativeParentQtWindow.isValid())
247 QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
252 const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
253 if (!isNonRegularWindow) {
254 auto iface =
qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
255 iface->runOnAndroidMainThread([=]() {
256 using namespace QtJniTypes;
257 auto activity = iface->context().object<Activity>();
258 if (states & Qt::WindowFullScreen)
259 QtWindowInsetsController::callStaticMethod(
"showFullScreen", activity);
260 else if (flags & Qt::ExpandedClientAreaHint)
261 QtWindowInsetsController::callStaticMethod(
"showExpanded", activity);
263 QtWindowInsetsController::callStaticMethod(
"showNormal", activity);
270 m_nativeQtWindow.callMethod<
void>(
"updateFocusedEditText");
275 return qApp->applicationState() > Qt::ApplicationHidden
276 && window()->isVisible()
277 && !window()->geometry().isEmpty();
284 region = QRect(QPoint(), geometry().size());
286 QWindowSystemInterface::handleExposeEvent(window(), region);
287 QWindowSystemInterface::flushWindowSystemEvents();
292 const bool windowStaysOnTop =
bool(window()->flags() & Qt::WindowStaysOnTopHint);
293 const bool isOpaque = !format().hasAlpha() && qFuzzyCompare(window()->opacity(), qreal(1.0));
295 m_nativeQtWindow.callMethod<
void>(
"createSurface", windowStaysOnTop, 32, isOpaque,
296 m_surfaceContainerType);
303 m_nativeQtWindow.callMethod<
void>(
"destroySurface");
311 const bool surfaceIsValid = surface.isValid();
312 qCDebug(lcQpaWindow) <<
"onSurfaceChanged(): valid Surface received" << surfaceIsValid;
313 m_androidSurfaceObject = surface;
314 if (surfaceIsValid) {
316 m_surfaceWaitCondition.wakeOne();
328 QRect availableGeometry = screen()->availableGeometry();
329 if (!geometry().isNull() && !availableGeometry.isNull()) {
330 QWindowSystemInterface::handleExposeEvent(window(),
331 QRegion(QRect(QPoint(), geometry().size())));
337 QWindow *modalWindow = QGuiApplication::modalWindow();
338 return modalWindow && modalWindow != window();
349 QtJniTypes::Surface surface)
357 const QList<QWindow*> windows =
qGuiApp->allWindows();
358 for (QWindow * window : windows) {
359 if (!window->handle())
361 QAndroidPlatformWindow *platformWindow =
362 static_cast<QAndroidPlatformWindow *>(window->handle());
363 const auto guard = platformWindow->destructionGuard();
364 if (!platformWindow->m_androidSurfaceCreated)
366 if (platformWindow->nativeViewId() == windowId)
367 platformWindow->onSurfaceChanged(surface);
372 jboolean focus, jint windowId)
378 qCWarning(lcQpaWindow,
379 "windowFocusChanged event received for non-existing window %d", windowId);
384 QWindowSystemInterface::handleFocusWindowChanged(window);
385 }
else if (!focus && window ==
qGuiApp->focusWindow()) {
387 QWindowSystemInterface::handleFocusWindowChanged(
nullptr);
392 QtJniTypes::Insets insets, jint id)
400 if (!insets.isValid())
404 for (QWindow *window :
qGuiApp->allWindows()) {
405 if (!window->handle())
407 QAndroidPlatformWindow *pw =
static_cast<QAndroidPlatformWindow *>(window->handle());
408 if (pw->nativeViewId() == id) {
417 QMargins safeMargins = QMargins(
418 insets.getField<
int>(
"left"),
419 insets.getField<
int>(
"top"),
420 insets.getField<
int>(
"right"),
421 insets.getField<
int>(
"bottom"));
423 if (safeMargins != pWindow->safeAreaMargins()) {
424 pWindow->setSafeAreaMargins(safeMargins);
425 QWindowSystemInterface::handleSafeAreaMarginsChanged(pWindow->window());
434 if (QGuiApplication::instance() !=
nullptr) {
435 const auto tlw = QGuiApplication::topLevelWindows();
436 for (QWindow *w : tlw) {
442 const QRect availableGeometry = w->screen()->availableGeometry();
443 const QRect geometry = w->geometry();
444 const bool isPositiveGeometry = (geometry.width() > 0 && geometry.height() > 0);
445 const bool isPositiveAvailableGeometry =
446 (availableGeometry.width() > 0 && availableGeometry.height() > 0);
448 if (isPositiveGeometry && isPositiveAvailableGeometry) {
449 const QRegion region = QRegion(QRect(QPoint(), w->geometry().size()));
450 QWindowSystemInterface::handleExposeEvent(w, region);
455Q_DECLARE_JNI_NATIVE_METHOD(updateWindows)
458
459
460
461
462
463
464QMutexLocker<QMutex> QAndroidPlatformWindow::destructionGuard()
466 return QMutexLocker(&m_destructionMutex);
469Q_CONSTINIT
static QBasicAtomicInt g_surfacesCounter = Q_BASIC_ATOMIC_INITIALIZER(0);
473 return g_surfacesCounter.loadRelaxed();
478 g_surfacesCounter.fetchAndAddRelaxed(1);
483 int cur = g_surfacesCounter.loadRelaxed();
488 if (g_surfacesCounter.testAndSetRelaxed(cur, cur - 1))
495 if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
497 Q_JNI_NATIVE_METHOD(updateWindows),
498 Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
499 Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow),
500 Q_JNI_NATIVE_SCOPED_METHOD(safeAreaMarginsChanged, QAndroidPlatformWindow)
502 qCCritical(lcQpaWindow) <<
"RegisterNatives failed for"
503 << QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
Combined button and popup list for selecting options.
AndroidBackendRegister * backendRegister()
QWindow * windowFromId(int windowId)