Android: Add preliminary support for child windows
Update the manual test case for embedded windows to have native window on Android. There are still some sharp corners, for example: * The windows are implemented with SurfaceViews, which makes z-ordering with multiple of them a bit tricky. The Surfaces they instantiate are basically z-ordered to either be below everything, with a hole punched in the window, or on top of everything, with the Surfaces created later on top of the ones created earlier. Also, with the foreign views it looks like the native view is on top of the Surface, because it is created later. And since the child windows create their Surfaces before the parent, they would be behind the parent window, currently circumventing this with letting the parent be z-ordered behind everything, and the children on top of everything. A follow up commit addresses this by changing the native view class to TextureView when multiple windows are present. * Parent window always gets the touch events - fixed in a follow up commit * If a child window has a text edit, it does not receive focus when clicking on it Task-number: QTBUG-116187 Change-Id: I32188ec5e3d3fce9fd8e3a931e317d1e081f691c Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
0a92d881bb
commit
6ff88f97a6
@ -29,6 +29,7 @@ set(java_sources
|
||||
src/org/qtproject/qt/android/QtClipboardManager.java
|
||||
src/org/qtproject/qt/android/QtDisplayManager.java
|
||||
src/org/qtproject/qt/android/UsedFromNativeCode.java
|
||||
src/org/qtproject/qt/android/QtRootLayout.java
|
||||
src/org/qtproject/qt/android/QtWindow.java
|
||||
)
|
||||
|
||||
|
@ -59,7 +59,8 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate
|
||||
return dispatchHoverEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO do we want to have one QtAccessibilityDelegate for the whole app (QtRootLayout) or
|
||||
// e.g. one per window?
|
||||
public QtAccessibilityDelegate(QtLayout layout)
|
||||
{
|
||||
m_layout = layout;
|
||||
|
@ -37,13 +37,12 @@ class QtActivityDelegate
|
||||
{
|
||||
private Activity m_activity;
|
||||
|
||||
private QtLayout m_layout = null;
|
||||
private QtRootLayout m_layout = null;
|
||||
private HashMap<Integer, QtWindow> m_topLevelWindows;
|
||||
private ImageView m_splashScreen = null;
|
||||
private boolean m_splashScreenSticky = false;
|
||||
|
||||
private View m_dummyView = null;
|
||||
|
||||
private QtAccessibilityDelegate m_accessibilityDelegate = null;
|
||||
private QtDisplayManager m_displayManager = null;
|
||||
|
||||
@ -135,7 +134,7 @@ class QtActivityDelegate
|
||||
|
||||
private void initMembers()
|
||||
{
|
||||
m_layout = new QtLayout(m_activity);
|
||||
m_layout = new QtRootLayout(m_activity);
|
||||
m_membersInitialized = true;
|
||||
m_topLevelWindows = new HashMap<Integer, QtWindow>();
|
||||
|
||||
|
@ -30,37 +30,6 @@ class QtLayout extends ViewGroup
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh)
|
||||
{
|
||||
Activity activity = (Activity)getContext();
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
DisplayMetrics realMetrics = new DisplayMetrics();
|
||||
Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
|
||||
? activity.getWindowManager().getDefaultDisplay()
|
||||
: activity.getDisplay();
|
||||
|
||||
if (display == null)
|
||||
return;
|
||||
|
||||
display.getRealMetrics(realMetrics);
|
||||
if ((realMetrics.widthPixels > realMetrics.heightPixels) != (w > h)) {
|
||||
// This is an intermediate state during display rotation.
|
||||
// The new size is still reported for old orientation, while
|
||||
// realMetrics contain sizes for new orientation. Setting
|
||||
// such parameters will produce inconsistent results, so
|
||||
// we just skip them.
|
||||
// We will have another onSizeChanged() with normal values
|
||||
// a bit later.
|
||||
return;
|
||||
}
|
||||
|
||||
QtDisplayManager.setApplicationDisplayMetrics(activity, w, h);
|
||||
QtDisplayManager.handleOrientationChanges(activity, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
@ -79,11 +48,15 @@ class QtLayout extends ViewGroup
|
||||
int childRight;
|
||||
int childBottom;
|
||||
|
||||
QtLayout.LayoutParams lp
|
||||
= (QtLayout.LayoutParams) child.getLayoutParams();
|
||||
|
||||
childRight = lp.x + child.getMeasuredWidth();
|
||||
childBottom = lp.y + child.getMeasuredHeight();
|
||||
if (child.getLayoutParams() instanceof QtLayout.LayoutParams) {
|
||||
QtLayout.LayoutParams lp
|
||||
= (QtLayout.LayoutParams) child.getLayoutParams();
|
||||
childRight = lp.x + child.getMeasuredWidth();
|
||||
childBottom = lp.y + child.getMeasuredHeight();
|
||||
} else {
|
||||
childRight = child.getMeasuredWidth();
|
||||
childBottom = child.getMeasuredHeight();
|
||||
}
|
||||
|
||||
maxWidth = Math.max(maxWidth, childRight);
|
||||
maxHeight = Math.max(maxHeight, childBottom);
|
||||
@ -181,6 +154,11 @@ class QtLayout extends ViewGroup
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height)
|
||||
{
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@ -0,0 +1,74 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
package org.qtproject.qt.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
|
||||
/**
|
||||
A layout which corresponds to one Activity, i.e. is the root layout where the top level window
|
||||
and handles orientation changes.
|
||||
*/
|
||||
public class QtRootLayout extends QtLayout
|
||||
{
|
||||
|
||||
private int m_activityDisplayRotation = -1;
|
||||
private int m_ownDisplayRotation = -1;
|
||||
private int m_nativeOrientation = -1;
|
||||
|
||||
public QtRootLayout(Context context)
|
||||
{
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void setActivityDisplayRotation(int rotation)
|
||||
{
|
||||
m_activityDisplayRotation = rotation;
|
||||
}
|
||||
|
||||
public void setNativeOrientation(int orientation)
|
||||
{
|
||||
m_nativeOrientation = orientation;
|
||||
}
|
||||
|
||||
public int displayRotation()
|
||||
{
|
||||
return m_ownDisplayRotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged (int w, int h, int oldw, int oldh)
|
||||
{
|
||||
Activity activity = (Activity)getContext();
|
||||
if (activity == null)
|
||||
return;
|
||||
|
||||
DisplayMetrics realMetrics = new DisplayMetrics();
|
||||
Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
|
||||
? activity.getWindowManager().getDefaultDisplay()
|
||||
: activity.getDisplay();
|
||||
|
||||
if (display == null)
|
||||
return;
|
||||
|
||||
display.getRealMetrics(realMetrics);
|
||||
if ((realMetrics.widthPixels > realMetrics.heightPixels) != (w > h)) {
|
||||
// This is an intermediate state during display rotation.
|
||||
// The new size is still reported for old orientation, while
|
||||
// realMetrics contain sizes for new orientation. Setting
|
||||
// such parameters will produce inconsistent results, so
|
||||
// we just skip them.
|
||||
// We will have another onSizeChanged() with normal values
|
||||
// a bit later.
|
||||
return;
|
||||
}
|
||||
|
||||
QtDisplayManager.setApplicationDisplayMetrics(activity, w, h);
|
||||
QtDisplayManager.handleOrientationChanges(activity, true);
|
||||
}
|
||||
}
|
@ -4,8 +4,6 @@
|
||||
package org.qtproject.qt.android;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
@ -18,14 +16,26 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba
|
||||
|
||||
private QtSurface m_surface;
|
||||
private View m_nativeView;
|
||||
private Handler m_androidHandler;
|
||||
private HashMap<Integer, QtWindow> m_childWindows = new HashMap<Integer, QtWindow>();
|
||||
private QtWindow m_parentWindow;
|
||||
|
||||
private static native void setSurface(int windowId, Surface surface);
|
||||
|
||||
public QtWindow(Context context)
|
||||
public QtWindow(Context context, QtWindow parentWindow)
|
||||
{
|
||||
super(context);
|
||||
setId(View.generateViewId());
|
||||
|
||||
setParent(parentWindow);
|
||||
}
|
||||
|
||||
void setVisible(boolean visible) {
|
||||
QtNative.runAction(() -> {
|
||||
if (visible)
|
||||
setVisibility(View.VISIBLE);
|
||||
else
|
||||
setVisibility(View.INVISIBLE);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -34,6 +44,12 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba
|
||||
setSurface(getId(), surface);
|
||||
}
|
||||
|
||||
public void removeWindow()
|
||||
{
|
||||
if (m_parentWindow != null)
|
||||
m_parentWindow.removeChildWindow(getId());
|
||||
}
|
||||
|
||||
public void createSurface(final boolean onTop,
|
||||
final int x, final int y, final int w, final int h,
|
||||
final int imageDepth)
|
||||
@ -44,11 +60,20 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba
|
||||
if (m_surface != null)
|
||||
removeView(m_surface);
|
||||
|
||||
QtSurface surface = new QtSurface(getContext(),
|
||||
QtWindow.this, QtWindow.this.getId(),
|
||||
onTop, imageDepth);
|
||||
surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||
setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||
// TODO currently setting child windows to onTop, since their surfaces
|
||||
// now get created earlier than the parents -> they are behind the parent window
|
||||
// without this, and SurfaceView z-ordering is limited
|
||||
boolean tempOnTop = onTop || (m_parentWindow != null);
|
||||
|
||||
QtSurface surface = new QtSurface(getContext(), QtWindow.this,
|
||||
QtWindow.this.getId(), tempOnTop, imageDepth);
|
||||
surface.setLayoutParams(new QtLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
|
||||
// The QtSurface of this window will be added as the first of the stack.
|
||||
// All other views are stacked based on the order they are created.
|
||||
addView(surface, 0);
|
||||
m_surface = surface;
|
||||
}
|
||||
@ -68,16 +93,34 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba
|
||||
});
|
||||
}
|
||||
|
||||
public void setSurfaceGeometry(final int x, final int y, final int w, final int h)
|
||||
public void setGeometry(final int x, final int y, final int w, final int h)
|
||||
{
|
||||
QtNative.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
QtLayout.LayoutParams lp = new QtLayout.LayoutParams(w, h, x, y);
|
||||
if (m_surface != null)
|
||||
m_surface.setLayoutParams(lp);
|
||||
else if (m_nativeView != null)
|
||||
m_nativeView.setLayoutParams(lp);
|
||||
QtWindow.this.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addChildWindow(QtWindow window)
|
||||
{
|
||||
QtNative.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
m_childWindows.put(window.getId(), window);
|
||||
addView(window, getChildCount());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeChildWindow(int id)
|
||||
{
|
||||
QtNative.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (m_childWindows.containsKey(id))
|
||||
removeView(m_childWindows.remove(id));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -92,13 +135,35 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba
|
||||
removeView(m_nativeView);
|
||||
|
||||
m_nativeView = view;
|
||||
m_nativeView.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||
|
||||
QtWindow.this.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||
m_nativeView.setLayoutParams(new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
addView(m_nativeView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void bringChildToFront(int id)
|
||||
{
|
||||
View view = m_childWindows.get(id);
|
||||
if (view != null) {
|
||||
if (getChildCount() > 0)
|
||||
moveChild(view, getChildCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void bringChildToBack(int id) {
|
||||
QtNative.runAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
View view = m_childWindows.get(id);
|
||||
if (view != null) {
|
||||
moveChild(view, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeNativeView()
|
||||
{
|
||||
QtNative.runAction(new Runnable() {
|
||||
@ -111,4 +176,22 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setParent(QtWindow parentWindow)
|
||||
{
|
||||
if (m_parentWindow == parentWindow)
|
||||
return;
|
||||
|
||||
if (m_parentWindow != null)
|
||||
m_parentWindow.removeChildWindow(getId());
|
||||
|
||||
m_parentWindow = parentWindow;
|
||||
if (m_parentWindow != null)
|
||||
m_parentWindow.addChildWindow(this);
|
||||
}
|
||||
|
||||
QtWindow parent()
|
||||
{
|
||||
return m_parentWindow;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect)
|
||||
QAndroidPlatformWindow::setGeometry(rect);
|
||||
|
||||
if (m_nativeViewInserted)
|
||||
setSurfaceGeometry(rect);
|
||||
setNativeGeometry(rect);
|
||||
}
|
||||
|
||||
void QAndroidPlatformForeignWindow::setVisible(bool visible)
|
||||
@ -63,11 +63,6 @@ void QAndroidPlatformForeignWindow::applicationStateChanged(Qt::ApplicationState
|
||||
QAndroidPlatformWindow::applicationStateChanged(state);
|
||||
}
|
||||
|
||||
void QAndroidPlatformForeignWindow::setParent(const QPlatformWindow *window)
|
||||
{
|
||||
Q_UNUSED(window);
|
||||
}
|
||||
|
||||
void QAndroidPlatformForeignWindow::addViewToWindow()
|
||||
{
|
||||
jint x = 0, y = 0, w = -1, h = -1;
|
||||
|
@ -20,7 +20,6 @@ public:
|
||||
void setGeometry(const QRect &rect) override;
|
||||
void setVisible(bool visible) override;
|
||||
void applicationStateChanged(Qt::ApplicationState state) override;
|
||||
void setParent(const QPlatformWindow *window) override;
|
||||
bool isForeignWindow() const override { return true; }
|
||||
|
||||
private:
|
||||
|
@ -45,7 +45,9 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
|
||||
m_oldGeometry = geometry();
|
||||
|
||||
QAndroidPlatformWindow::setGeometry(rect);
|
||||
setSurfaceGeometry(rect);
|
||||
|
||||
|
||||
setNativeGeometry(rect);
|
||||
|
||||
QRect availableGeometry = screen()->availableGeometry();
|
||||
if (rect.width() > 0
|
||||
@ -59,7 +61,7 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
|
||||
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
|
||||
{
|
||||
if (QAndroidEventDispatcherStopper::stopped() ||
|
||||
QGuiApplication::applicationState() == Qt::ApplicationSuspended || !window()->isTopLevel()) {
|
||||
QGuiApplication::applicationState() == Qt::ApplicationSuspended) {
|
||||
return m_eglSurface;
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,6 @@ public:
|
||||
void removeWindow(QAndroidPlatformWindow *window);
|
||||
void raise(QAndroidPlatformWindow *window);
|
||||
void lower(QAndroidPlatformWindow *window);
|
||||
|
||||
void topVisibleWindowChanged();
|
||||
int displayId() const override;
|
||||
|
||||
|
@ -39,7 +39,8 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
|
||||
m_oldGeometry = geometry();
|
||||
|
||||
QAndroidPlatformWindow::setGeometry(rect);
|
||||
setSurfaceGeometry(rect);
|
||||
if (m_surfaceCreated)
|
||||
setNativeGeometry(rect);
|
||||
|
||||
QRect availableGeometry = screen()->availableGeometry();
|
||||
if (rect.width() > 0
|
||||
|
@ -19,10 +19,9 @@ Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window")
|
||||
Q_CONSTINIT static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0);
|
||||
|
||||
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
|
||||
: QPlatformWindow(window), m_nativeQtWindow(QNativeInterface::QAndroidApplication::context()),
|
||||
: QPlatformWindow(window), m_nativeQtWindow(nullptr), m_nativeParentQtWindow(nullptr),
|
||||
m_androidSurfaceObject(nullptr)
|
||||
{
|
||||
m_nativeViewId = m_nativeQtWindow.callMethod<jint>("getId");
|
||||
m_windowFlags = Qt::Widget;
|
||||
m_windowState = Qt::WindowNoState;
|
||||
// the surfaceType is overwritten in QAndroidPlatformOpenGLWindow ctor so let's save
|
||||
@ -48,22 +47,44 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
|
||||
if (requestedNativeGeometry != finalNativeGeometry)
|
||||
setGeometry(finalNativeGeometry);
|
||||
}
|
||||
platformScreen()->addWindow(this);
|
||||
|
||||
if (parent())
|
||||
m_nativeParentQtWindow = static_cast<QAndroidPlatformWindow*>(parent())->nativeWindow();
|
||||
|
||||
QNativeInterface::QAndroidApplication::runOnAndroidMainThread([this]() {
|
||||
m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
|
||||
QNativeInterface::QAndroidApplication::context(),
|
||||
m_nativeParentQtWindow);
|
||||
m_nativeViewId = m_nativeQtWindow.callMethod<jint>("getId");
|
||||
}).waitForFinished();
|
||||
|
||||
if (window->isTopLevel())
|
||||
platformScreen()->addWindow(this);
|
||||
}
|
||||
|
||||
QAndroidPlatformWindow::~QAndroidPlatformWindow()
|
||||
{
|
||||
platformScreen()->removeWindow(this);
|
||||
if (window()->isTopLevel())
|
||||
platformScreen()->removeWindow(this);
|
||||
}
|
||||
|
||||
|
||||
void QAndroidPlatformWindow::lower()
|
||||
{
|
||||
if (m_nativeParentQtWindow.isValid()) {
|
||||
m_nativeParentQtWindow.callMethod<void>("bringChildToBack", nativeViewId());
|
||||
return;
|
||||
}
|
||||
platformScreen()->lower(this);
|
||||
}
|
||||
|
||||
void QAndroidPlatformWindow::raise()
|
||||
{
|
||||
if (m_nativeParentQtWindow.isValid()) {
|
||||
m_nativeParentQtWindow.callMethod<void>("bringChildToFront", nativeViewId());
|
||||
QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
|
||||
return;
|
||||
}
|
||||
updateSystemUiVisibility();
|
||||
platformScreen()->raise(this);
|
||||
}
|
||||
@ -87,16 +108,20 @@ void QAndroidPlatformWindow::setGeometry(const QRect &rect)
|
||||
|
||||
void QAndroidPlatformWindow::setVisible(bool visible)
|
||||
{
|
||||
m_nativeQtWindow.callMethod<void>("setVisible", visible);
|
||||
|
||||
if (visible) {
|
||||
updateSystemUiVisibility();
|
||||
if ((m_windowState & Qt::WindowFullScreen)
|
||||
|| ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) {
|
||||
setGeometry(platformScreen()->geometry());
|
||||
} else if (m_windowState & Qt::WindowMaximized) {
|
||||
setGeometry(platformScreen()->availableGeometry());
|
||||
if (window()->isTopLevel()) {
|
||||
updateSystemUiVisibility();
|
||||
if ((m_windowState & Qt::WindowFullScreen)
|
||||
|| ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) {
|
||||
setGeometry(platformScreen()->geometry());
|
||||
} else if (m_windowState & Qt::WindowMaximized) {
|
||||
setGeometry(platformScreen()->availableGeometry());
|
||||
}
|
||||
requestActivateWindow();
|
||||
}
|
||||
requestActivateWindow();
|
||||
} else if (window() == qGuiApp->focusWindow()) {
|
||||
} else if (window()->isTopLevel() && window() == qGuiApp->focusWindow()) {
|
||||
platformScreen()->topVisibleWindowChanged();
|
||||
}
|
||||
|
||||
@ -132,13 +157,22 @@ Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const
|
||||
|
||||
void QAndroidPlatformWindow::setParent(const QPlatformWindow *window)
|
||||
{
|
||||
// even though we do not yet support child windows properly, any windows getting a parent
|
||||
// should be removed from screen's window stack which is only for top level windows,
|
||||
// and respectively any window becoming top level should go in there
|
||||
using namespace QtJniTypes;
|
||||
if (window) {
|
||||
platformScreen()->removeWindow(this);
|
||||
// If we were a top level window, remove from screen
|
||||
if (!m_nativeParentQtWindow.isValid())
|
||||
platformScreen()->removeWindow(this);
|
||||
|
||||
const QAndroidPlatformWindow *androidWindow =
|
||||
static_cast<const QAndroidPlatformWindow*>(window);
|
||||
const QtWindow parentWindow = androidWindow->nativeWindow();
|
||||
// If this was a child window of another window, the java method takes care of that
|
||||
m_nativeQtWindow.callMethod<void, QtWindow>("setParent", parentWindow.object());
|
||||
m_nativeParentQtWindow = parentWindow;
|
||||
} else {
|
||||
m_nativeQtWindow.callMethod<void, QtWindow>("setParent", nullptr);
|
||||
platformScreen()->addWindow(this);
|
||||
m_nativeParentQtWindow = QJniObject();
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,6 +188,7 @@ void QAndroidPlatformWindow::propagateSizeHints()
|
||||
|
||||
void QAndroidPlatformWindow::requestActivateWindow()
|
||||
{
|
||||
// raise() will handle differences between top level and child windows, and requesting focus
|
||||
if (!blockedByModal())
|
||||
raise();
|
||||
}
|
||||
@ -214,7 +249,7 @@ void QAndroidPlatformWindow::destroySurface()
|
||||
}
|
||||
}
|
||||
|
||||
void QAndroidPlatformWindow::setSurfaceGeometry(const QRect &geometry)
|
||||
void QAndroidPlatformWindow::setNativeGeometry(const QRect &geometry)
|
||||
{
|
||||
if (!m_surfaceCreated)
|
||||
return;
|
||||
@ -229,7 +264,7 @@ void QAndroidPlatformWindow::setSurfaceGeometry(const QRect &geometry)
|
||||
w = geometry.width();
|
||||
h = geometry.height();
|
||||
}
|
||||
m_nativeQtWindow.callMethod<void>("setSurfaceGeometry", x, y, w, h);
|
||||
m_nativeQtWindow.callMethod<void>("setGeometry", x, y, w, h);
|
||||
}
|
||||
|
||||
void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface)
|
||||
|
@ -65,7 +65,7 @@ protected:
|
||||
void unlockSurface() { m_surfaceMutex.unlock(); }
|
||||
void createSurface();
|
||||
void destroySurface();
|
||||
void setSurfaceGeometry(const QRect &geometry);
|
||||
void setNativeGeometry(const QRect &geometry);
|
||||
void sendExpose() const;
|
||||
bool blockedByModal() const;
|
||||
|
||||
@ -76,6 +76,7 @@ protected:
|
||||
WId m_windowId;
|
||||
|
||||
QtJniTypes::QtWindow m_nativeQtWindow;
|
||||
QtJniTypes::QtWindow m_nativeParentQtWindow;
|
||||
// The Android Surface, accessed from multiple threads, guarded by m_surfaceMutex
|
||||
QtJniTypes::Surface m_androidSurfaceObject;
|
||||
QWaitCondition m_surfaceWaitCondition;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_OS_WIN) || QT_CONFIG(xcb)
|
||||
#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_OS_WIN) || QT_CONFIG(xcb) || defined(ANDROID)
|
||||
#include "../../shared/nativewindow.h"
|
||||
#define HAVE_NATIVE_WINDOW
|
||||
#endif
|
||||
|
@ -14,6 +14,12 @@
|
||||
# include <winuser.h>
|
||||
#elif QT_CONFIG(xcb)
|
||||
# include <xcb/xcb.h>
|
||||
#elif defined(ANDROID)
|
||||
# include <QtCore/qjniobject.h>
|
||||
# include <QtCore/qjnitypes.h>
|
||||
# include <QtCore/qnativeinterface.h>
|
||||
Q_DECLARE_JNI_CLASS(View, "android/view/View")
|
||||
Q_DECLARE_JNI_CLASS(ViewParent, "android/view/ViewParent")
|
||||
#endif
|
||||
|
||||
class NativeWindow
|
||||
@ -28,6 +34,8 @@ public:
|
||||
using Handle = HWND;
|
||||
#elif QT_CONFIG(xcb)
|
||||
using Handle = xcb_window_t;
|
||||
#elif defined(ANDROID)
|
||||
using Handle = QtJniTypes::View;;
|
||||
#endif
|
||||
|
||||
NativeWindow();
|
||||
@ -249,6 +257,48 @@ void NativeWindow::setParent(WId parent)
|
||||
parent ? Handle(parent) : screen->root, 0, 0);
|
||||
}
|
||||
|
||||
#elif defined (ANDROID)
|
||||
NativeWindow::NativeWindow()
|
||||
{
|
||||
m_handle = QJniObject::construct<QtJniTypes::View, QtJniTypes::Context>(
|
||||
QNativeInterface::QAndroidApplication::context());
|
||||
m_handle.callMethod<void>("setBackgroundColor", 0xffffaaff);
|
||||
}
|
||||
|
||||
NativeWindow::~NativeWindow()
|
||||
{
|
||||
}
|
||||
|
||||
NativeWindow::operator WId() const
|
||||
{
|
||||
return reinterpret_cast<WId>(m_handle.object());
|
||||
}
|
||||
|
||||
void NativeWindow::setGeometry(const QRect &rect)
|
||||
{
|
||||
// No-op, the view geometry is handled by the QWindow constructed from it
|
||||
}
|
||||
|
||||
QRect NativeWindow::geometry() const
|
||||
{
|
||||
int x = m_handle.callMethod<jint>("getX");
|
||||
int y = m_handle.callMethod<jint>("getY");
|
||||
int w = m_handle.callMethod<jint>("getWidth");
|
||||
int h = m_handle.callMethod<jint>("getHeight");
|
||||
return QRect(x, y, w, h);
|
||||
}
|
||||
|
||||
WId NativeWindow::parentWinId() const
|
||||
{
|
||||
// TODO note, the returned object is a ViewParent, not necessarily
|
||||
// a View - what is this used for?
|
||||
using namespace QtJniTypes;
|
||||
ViewParent parentView = m_handle.callMethod<ViewParent>("getParent");
|
||||
if (parentView.isValid())
|
||||
return reinterpret_cast<WId>(parentView.object());
|
||||
return 0L;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // NATIVEWINDOW_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user