summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernd Weimer <bernd.weimer@pelagicore.com>2017-10-16 16:11:22 +0200
committerRobert Griebl <robert.griebl@pelagicore.com>2017-11-27 15:59:25 +0000
commite6d5d275f3fa7057701c19b3a399a49dcd073e51 (patch)
treeb04071790269299c1fd6c4c2a3d5b1abcb9ce9b9
parent4d205ac87daeedbb34d0d886c762d5834aa434fb (diff)
Hide properties in FakeApplicationManagerWindow
To mitigate the difference between single- and multi-process mode, properties and signals in FakeApplicationManagerWindow (Item) will be hidden, that are not available in ApplicationManagerWindow (Window). The same warnings will be printed and applications will not start, which use such properties. This patch only hides "parent" - it provides a base for further properties that will be hidden. To achieve this an InProcessSurfaceItem has been introduced that is actually exposed to the systemUI and serves as an item parent for FakeApplicationManagerWindows. Also changed the lifetime of the application's object hierarchy. Task-number: AUTOSUITE-143 Change-Id: Ib4881ec39267907fb24bebbd167796270661ab8c Reviewed-by: Robert Griebl <robert.griebl@pelagicore.com>
-rw-r--r--src/manager-lib/abstractruntime.cpp7
-rw-r--r--src/manager-lib/abstractruntime.h4
-rw-r--r--src/manager-lib/fakeapplicationmanagerwindow.cpp127
-rw-r--r--src/manager-lib/fakeapplicationmanagerwindow.h20
-rw-r--r--src/manager-lib/inprocesssurfaceitem.cpp76
-rw-r--r--src/manager-lib/inprocesssurfaceitem.h78
-rw-r--r--src/manager-lib/manager-lib.pro2
-rw-r--r--src/manager-lib/qmlinprocessruntime.cpp147
-rw-r--r--src/manager-lib/qmlinprocessruntime.h9
-rw-r--r--src/window-lib/inprocesswindow.cpp31
-rw-r--r--src/window-lib/inprocesswindow.h4
-rw-r--r--src/window-lib/windowmanager.cpp5
-rw-r--r--src/window-lib/windowmanager.h2
-rw-r--r--tests/qml/fakeamwindow/am-config.yaml15
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent1/icon.pngbin0 -> 1486 bytes
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent1/info.yaml9
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent1/parent1.qml46
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent2/icon.pngbin0 -> 1486 bytes
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent2/info.yaml9
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent2/parent2.qml61
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent3/Test.qml46
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent3/icon.pngbin0 -> 1486 bytes
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent3/info.yaml9
-rw-r--r--tests/qml/fakeamwindow/apps/test.famw.parent3/parent3.qml59
-rw-r--r--tests/qml/fakeamwindow/fakeamwindow.pro4
-rw-r--r--tests/qml/fakeamwindow/tst_fakeamwindow.qml79
-rw-r--r--tests/qml/qml.pro3
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml47
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.loader/icon.pngbin0 -> 1486 bytes
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.loader/info.yaml9
-rw-r--r--tests/qml/windowmapping/apps/test.winmap.loader/loader.qml64
-rw-r--r--tests/qml/windowmapping/tst_windowmapping.qml151
32 files changed, 942 insertions, 181 deletions
diff --git a/src/manager-lib/abstractruntime.cpp b/src/manager-lib/abstractruntime.cpp
index 521ea49b..c9f63987 100644
--- a/src/manager-lib/abstractruntime.cpp
+++ b/src/manager-lib/abstractruntime.cpp
@@ -93,6 +93,13 @@ QVariantMap AbstractRuntime::systemProperties() const
return QVariantMap();
}
+#if !defined(AM_HEADLESS)
+void AbstractRuntime::inProcessSurfaceItemReleased(QQuickItem *)
+{
+ // generally there is nothing to do
+}
+#endif
+
QByteArray AbstractRuntime::securityToken() const
{
return m_securityToken;
diff --git a/src/manager-lib/abstractruntime.h b/src/manager-lib/abstractruntime.h
index eddfd703..a6cad10b 100644
--- a/src/manager-lib/abstractruntime.h
+++ b/src/manager-lib/abstractruntime.h
@@ -133,6 +133,10 @@ public:
virtual bool start() = 0;
virtual void stop(bool forceKill = false) = 0;
+#if !defined(AM_HEADLESS)
+ virtual void inProcessSurfaceItemReleased(QQuickItem *);
+#endif
+
signals:
void stateChanged(QT_PREPEND_NAMESPACE_AM(AbstractRuntime::State) newState);
void finished(int exitCode, QProcess::ExitStatus status);
diff --git a/src/manager-lib/fakeapplicationmanagerwindow.cpp b/src/manager-lib/fakeapplicationmanagerwindow.cpp
index 546ee569..c6a8a736 100644
--- a/src/manager-lib/fakeapplicationmanagerwindow.cpp
+++ b/src/manager-lib/fakeapplicationmanagerwindow.cpp
@@ -41,25 +41,65 @@
#include "logging.h"
#include "fakeapplicationmanagerwindow.h"
+#include "inprocesssurfaceitem.h"
#include "qmlinprocessruntime.h"
#include <QSGSimpleRectNode>
#include <QQmlComponent>
+#include <QQmlEngine>
+#include <QQmlContext>
+#include <QQmlInfo>
#include <private/qqmlcomponentattached_p.h>
QT_BEGIN_NAMESPACE_AM
+static QByteArray nameToKey(const QString &name)
+{
+ return QByteArray("_am_") + name.toUtf8();
+}
+
+static QString keyToName(const QByteArray &key)
+{
+ return QString::fromUtf8(key.mid(4));
+}
+
+static bool isName(const QByteArray &key)
+{
+ return key.startsWith("_am_");
+}
+
+
FakeApplicationManagerWindow::FakeApplicationManagerWindow(QQuickItem *parent)
: QQuickItem(parent)
+ , m_windowProperties(new QObject)
{
- qCDebug(LogSystem) << "FakeApplicationManagerWindow ctor! this:" << this;
setFlag(ItemHasContents);
connect(this, &QQuickItem::visibleChanged, this, &FakeApplicationManagerWindow::onVisibleChanged);
+
+ m_windowProperties.data()->installEventFilter(this);
}
FakeApplicationManagerWindow::~FakeApplicationManagerWindow()
{
- qCDebug(LogSystem) << "FakeApplicationManagerWindow dtor! this: " << this;
+ if (m_surfaceItem) {
+ m_runtime->removeWindow(this);
+ m_surfaceItem->m_contentItem = nullptr;
+ }
+}
+
+bool FakeApplicationManagerWindow::isFakeVisible() const
+{
+ return m_fakeVisible;
+}
+
+void FakeApplicationManagerWindow::setFakeVisible(bool visible)
+{
+ if (visible != m_fakeVisible) {
+ m_fakeVisible = visible;
+ setVisible(visible);
+ if (m_surfaceItem)
+ m_surfaceItem->setVisible(visible);
+ }
}
QColor FakeApplicationManagerWindow::color() const
@@ -94,45 +134,27 @@ void FakeApplicationManagerWindow::showNormal()
// doesn't work in wayland right now, so do nothing... revisit later (after andies resize-redesign)
}
-
-
-static QByteArray nameToKey(const QString &name)
-{
- return QByteArray("_am_") + name.toUtf8();
-}
-
-static QString keyToName(const QByteArray &key)
-{
- return QString::fromUtf8(key.mid(4));
-}
-
-static bool isName(const QByteArray &key)
-{
- return key.startsWith("_am_");
-}
-
-
bool FakeApplicationManagerWindow::setWindowProperty(const QString &name, const QVariant &value)
{
QByteArray key = nameToKey(name);
- QVariant oldValue = property(key);
+ QVariant oldValue = m_windowProperties->property(key);
bool changed = !oldValue.isValid() || (oldValue != value);
- if (changed) {
- setProperty(key, value);
- }
+ if (changed)
+ m_windowProperties->setProperty(key, value);
+
return true;
}
QVariant FakeApplicationManagerWindow::windowProperty(const QString &name) const
{
QByteArray key = nameToKey(name);
- return property(key);
+ return m_windowProperties->property(key);
}
QVariantMap FakeApplicationManagerWindow::windowProperties() const
{
- const QList<QByteArray> keys = dynamicPropertyNames();
+ const QList<QByteArray> keys = m_windowProperties->dynamicPropertyNames();
QVariantMap map;
for (const QByteArray &key : keys) {
@@ -140,27 +162,25 @@ QVariantMap FakeApplicationManagerWindow::windowProperties() const
continue;
QString name = keyToName(key);
- map[name] = property(key);
+ map[name] = m_windowProperties->property(key);
}
return map;
}
-bool FakeApplicationManagerWindow::event(QEvent *e)
+bool FakeApplicationManagerWindow::eventFilter(QObject *o, QEvent *e)
{
- if (e->type() == QEvent::DynamicPropertyChange) {
+ if ((o == m_windowProperties) && (e->type() == QEvent::DynamicPropertyChange)) {
QDynamicPropertyChangeEvent *dpce = static_cast<QDynamicPropertyChangeEvent *>(e);
QByteArray key = dpce->propertyName();
if (isName(key)) {
QString name = keyToName(dpce->propertyName());
- emit windowPropertyChanged(name, property(key));
-
- //qWarning() << "FPW: got change" << name << " --> " << property(key).toString();
+ emit windowPropertyChanged(name, m_windowProperties->property(key));
}
}
- return QQuickItem::event(e);
+ return QQuickItem::eventFilter(o, e);
}
QSGNode *FakeApplicationManagerWindow::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
@@ -173,17 +193,24 @@ QSGNode *FakeApplicationManagerWindow::updatePaintNode(QSGNode *oldNode, QQuickI
return node;
}
+void FakeApplicationManagerWindow::determineRuntime()
+{
+ if (!m_runtime) {
+ QQmlContext *ctx = QQmlEngine::contextForObject(this);
+ while (ctx && !m_runtime) {
+ if (ctx->property(QmlInProcessRuntime::s_runtimeKey).isValid())
+ m_runtime = ctx->property(QmlInProcessRuntime::s_runtimeKey).value<QmlInProcessRuntime*>();
+ ctx = ctx->parentContext();
+ }
+ }
+}
+
void FakeApplicationManagerWindow::componentComplete()
{
qCDebug(LogSystem) << "FakeApplicationManagerWindow componentComplete() this:" << this;
QQuickItem::componentComplete();
-
- QObject *prnt = parent();
- while (prnt && !m_runtime) {
- m_runtime = prnt->property("AM-RUNTIME").value<QtAM::QmlInProcessRuntime*>();
- prnt = prnt->parent();
- }
+ determineRuntime();
// This part is scary, but we need to make sure that all Component.onComplete: handlers on
// the QML side have been run, before we hand this window over to the WindowManager for the
@@ -223,4 +250,26 @@ void FakeApplicationManagerWindow::onVisibleChanged()
m_runtime->addWindow(this);
}
+QJSValue FakeApplicationManagerWindow::getUndefined() const
+{
+ return QJSValue();
+}
+
+void FakeApplicationManagerWindow::connectNotify(const QMetaMethod &signal)
+{
+ static int parentMetaIdx = FakeApplicationManagerWindow::staticMetaObject.indexOfSignal("parentChanged(QQuickItem*)");
+
+ if (signal.methodIndex() == parentMetaIdx) {
+ determineRuntime();
+ if (m_runtime)
+ m_runtime->m_componentError = true;
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
+ qWarning() << "QML ApplicationManagerWindow: Cannot assign to non-existent property \"onParentChanged\"";
+#else
+ qmlWarning(this) << "Cannot assign to non-existent property \"onParentChanged\"";
+#endif
+ }
+}
+
QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/fakeapplicationmanagerwindow.h b/src/manager-lib/fakeapplicationmanagerwindow.h
index eed6112b..4a0b41d6 100644
--- a/src/manager-lib/fakeapplicationmanagerwindow.h
+++ b/src/manager-lib/fakeapplicationmanagerwindow.h
@@ -51,6 +51,7 @@ QT_FORWARD_DECLARE_CLASS(QQmlComponentAttached)
QT_BEGIN_NAMESPACE_AM
class QmlInProcessRuntime;
+class InProcessSurfaceItem;
class FakeApplicationManagerWindow : public QQuickItem
{
@@ -58,6 +59,8 @@ class FakeApplicationManagerWindow : public QQuickItem
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
Q_PROPERTY(QString title READ dummyGetterString WRITE dummySetterString)
+ Q_PROPERTY(bool visible READ isFakeVisible WRITE setFakeVisible NOTIFY visibleChanged FINAL)
+
// for API compatibility with QWaylandQuickItem - we cannot really simulate these,
// but at least the QML code will not throw errors due to missing properties.
Q_PROPERTY(bool paintEnabled READ dummyGetter WRITE dummySetter)
@@ -65,6 +68,8 @@ class FakeApplicationManagerWindow : public QQuickItem
Q_PROPERTY(bool inputEventsEnabled READ dummyGetter WRITE dummySetter)
Q_PROPERTY(bool focusOnClick READ dummyGetter WRITE dummySetter)
+ Q_PROPERTY(QJSValue parent READ getUndefined CONSTANT)
+
public:
explicit FakeApplicationManagerWindow(QQuickItem *parent = nullptr);
~FakeApplicationManagerWindow();
@@ -72,6 +77,9 @@ public:
QColor color() const;
void setColor(const QColor &c);
+ bool isFakeVisible() const;
+ void setFakeVisible(bool visible);
+
Q_INVOKABLE bool setWindowProperty(const QString &name, const QVariant &value);
Q_INVOKABLE QVariant windowProperty(const QString &name) const;
Q_INVOKABLE QVariantMap windowProperties() const;
@@ -109,24 +117,32 @@ signals:
void fakeNoFullScreenSignal(); // TODO this should be replaced by 'normal' and 'maximized' as soon as needed
void windowPropertyChanged(const QString &name, const QVariant &value);
void colorChanged();
+ void visibleChanged();
protected:
- bool event(QEvent *e) override;
+ bool eventFilter(QObject *o, QEvent *e) override;
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+ void connectNotify(const QMetaMethod &signal) override;
private:
bool dummyGetter() const { return false; }
void dummySetter(bool) { }
QString dummyGetterString() const { return QString(); }
void dummySetterString(const QString&) {}
+
+ void determineRuntime();
void onVisibleChanged();
+ QJSValue getUndefined() const;
+ InProcessSurfaceItem *m_surfaceItem = nullptr;
+ QSharedPointer<QObject> m_windowProperties;
QmlInProcessRuntime *m_runtime = nullptr;
QColor m_color;
-
+ bool m_fakeVisible = true;
QVector<QQmlComponentAttached *> m_attachedCompleteHandlers;
friend class QmlInProcessRuntime; // for setting the m_runtime member
+ friend class InProcessSurfaceItem;
};
QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/inprocesssurfaceitem.cpp b/src/manager-lib/inprocesssurfaceitem.cpp
new file mode 100644
index 00000000..a18808c4
--- /dev/null
+++ b/src/manager-lib/inprocesssurfaceitem.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "inprocesssurfaceitem.h"
+#include "fakeapplicationmanagerwindow.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+InProcessSurfaceItem::InProcessSurfaceItem(FakeApplicationManagerWindow *content)
+ : m_contentItem(content)
+{
+ content->m_surfaceItem = this;
+ m_windowProperties = content->m_windowProperties;
+ setParentItem(content->parentItem());
+ content->setParentItem(this);
+}
+
+InProcessSurfaceItem::~InProcessSurfaceItem()
+{
+ if (m_contentItem)
+ m_contentItem->m_surfaceItem = nullptr;
+}
+
+QSharedPointer<QObject> InProcessSurfaceItem::windowProperties()
+{
+ return m_windowProperties;
+}
+
+void InProcessSurfaceItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+ if (m_contentItem) {
+ m_contentItem->setWidth(newGeometry.width());
+ m_contentItem->setHeight(newGeometry.height());
+ }
+}
+
+QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/inprocesssurfaceitem.h b/src/manager-lib/inprocesssurfaceitem.h
new file mode 100644
index 00000000..b9da7447
--- /dev/null
+++ b/src/manager-lib/inprocesssurfaceitem.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#if !defined(AM_HEADLESS)
+
+#include <QQuickItem>
+#include <QtAppManCommon/global.h>
+
+QT_BEGIN_NAMESPACE_AM
+
+class FakeApplicationManagerWindow;
+
+/*
+ * Item exposed to the system UI, FakeApplicationManagerWindows will be wrapped inside those.
+ */
+class InProcessSurfaceItem : public QQuickItem
+{
+ Q_OBJECT
+public:
+ InProcessSurfaceItem(FakeApplicationManagerWindow *famw);
+ ~InProcessSurfaceItem();
+
+ QSharedPointer<QObject> windowProperties();
+
+protected:
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+private:
+ FakeApplicationManagerWindow *m_contentItem = nullptr;
+ QSharedPointer<QObject> m_windowProperties;
+
+ friend class QmlInProcessRuntime;
+ friend class FakeApplicationManagerWindow;
+};
+
+QT_END_NAMESPACE_AM
+
+#endif // !AM_HEADLESS
diff --git a/src/manager-lib/manager-lib.pro b/src/manager-lib/manager-lib.pro
index 221aa07d..93f728f8 100644
--- a/src/manager-lib/manager-lib.pro
+++ b/src/manager-lib/manager-lib.pro
@@ -43,6 +43,7 @@ linux:HEADERS += \
!headless:HEADERS += \
fakeapplicationmanagerwindow.h \
+ inprocesssurfaceitem.h
multi-process:HEADERS += \
nativeruntime.h \
@@ -74,6 +75,7 @@ linux:SOURCES += \
!headless:SOURCES += \
fakeapplicationmanagerwindow.cpp \
+ inprocesssurfaceitem.cpp
multi-process:SOURCES += \
nativeruntime.cpp \
diff --git a/src/manager-lib/qmlinprocessruntime.cpp b/src/manager-lib/qmlinprocessruntime.cpp
index 33364e97..51e7d0da 100644
--- a/src/manager-lib/qmlinprocessruntime.cpp
+++ b/src/manager-lib/qmlinprocessruntime.cpp
@@ -49,6 +49,7 @@
# include <QQuickView>
# include "fakeapplicationmanagerwindow.h"
+# include "inprocesssurfaceitem.h"
#endif
#include "logging.h"
@@ -96,6 +97,9 @@ static void loadDummyDataFiles(QQmlEngine &engine, const QString& directory)
}
+const char *QmlInProcessRuntime::s_runtimeKey = "_am_runtime";
+
+
QmlInProcessRuntime::QmlInProcessRuntime(const Application *app, QmlInProcessRuntimeManager *manager)
: AbstractRuntime(nullptr, app, manager)
{ }
@@ -105,21 +109,17 @@ QmlInProcessRuntime::~QmlInProcessRuntime()
#if !defined(AM_HEADLESS)
// if there is still a window present at this point, fire the 'closing' signal (probably) again,
// because it's still the duty of WindowManager together with qml-ui to free and delete this item!!
- for (int i = m_windows.size(); i; --i)
- emit inProcessSurfaceItemClosing(m_windows.at(i-1));
+ for (int i = m_surfaces.size(); i; --i)
+ emit inProcessSurfaceItemClosing(m_surfaces.at(i-1));
#endif
}
bool QmlInProcessRuntime::start()
{
- setState(Startup);
#if !defined(AM_HEADLESS)
- QQuickItem *win = qobject_cast<QQuickItem*>(m_rootObject);
- if (win) { // if there is already a window present, just emit ready signal and return true (=="start successful")
- emit inProcessSurfaceItemReady(win);
- return true;
- }
+ Q_ASSERT(!m_rootObject);
#endif
+ setState(Startup);
if (!m_inProcessQmlEngine)
return false;
@@ -144,6 +144,7 @@ bool QmlInProcessRuntime::start()
qCDebug(LogSystem) << "Updated Qml import paths:" << m_inProcessQmlEngine->importPathList();
}
+ m_componentError = false;
QQmlComponent *component = new QQmlComponent(m_inProcessQmlEngine, m_app->absoluteCodeFilePath());
if (!component->isReady()) {
@@ -157,41 +158,35 @@ bool QmlInProcessRuntime::start()
m_applicationIf = new QmlInProcessApplicationInterface(this);
appContext->setContextProperty(qSL("ApplicationInterface"), m_applicationIf);
connect(m_applicationIf, &QmlInProcessApplicationInterface::quitAcknowledged,
- this, [=]() { finish(0, QProcess::NormalExit); });
+ this, [this]() { finish(0, QProcess::NormalExit); });
- QObject *obj = component->beginCreate(appContext);
+ if (appContext->setProperty(s_runtimeKey, QVariant::fromValue(this)))
+ qCritical() << "Could not set" << s_runtimeKey << "property in QML context";
- if (!obj) {
- qCCritical(LogSystem) << "could not load" << m_app->absoluteCodeFilePath() << ": no root object";
- delete obj;
- delete appContext;
- delete m_applicationIf;
- m_applicationIf = nullptr;
- return false;
- }
+ QObject *obj = component->beginCreate(appContext);
+ QTimer::singleShot(0, this, [component, appContext, obj, this]() {
+ component->completeCreate();
+ if (!obj || m_componentError) {
+ qCCritical(LogSystem) << "could not load" << m_app->absoluteCodeFilePath() << ": no root object";
+ delete obj;
+ delete appContext;
+ delete m_applicationIf;
+ m_applicationIf = nullptr;
+ finish(3, QProcess::NormalExit);
+ } else {
#if !defined(AM_HEADLESS)
-
- FakeApplicationManagerWindow *window = qobject_cast<FakeApplicationManagerWindow*>(obj);
- if (window) {
- window->m_runtime = this;
- } else {
- QQuickItem *item = qobject_cast<QQuickItem*>(obj);
- if (item)
- addWindow(item);
- }
- Q_ASSERT(obj->metaObject()->indexOfProperty("AM-RUNTIME") == -1);
- if (obj->setProperty("AM-RUNTIME", QVariant::fromValue(this)))
- qCritical() << "ApplicationManagerWindow must not have an AM-RUNTIME property";
- m_rootObject = obj;
-
+ if (!qobject_cast<FakeApplicationManagerWindow*>(obj)) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(obj);
+ if (item)
+ addWindow(item);
+ }
+ m_rootObject = obj;
#endif
-
- QTimer::singleShot(0, this, [component, this]() {
- component->completeCreate();
- if (!m_document.isEmpty())
- openDocument(m_document, QString());
- setState(Active);
+ if (!m_document.isEmpty())
+ openDocument(m_document, QString());
+ setState(Active);
+ }
delete component;
});
return true;
@@ -203,10 +198,13 @@ void QmlInProcessRuntime::stop(bool forceKill)
emit aboutToStop();
#if !defined(AM_HEADLESS)
- for (int i = m_windows.size(); i; --i)
- emit inProcessSurfaceItemClosing(m_windows.at(i-1));
- m_windows.clear();
- m_rootObject = nullptr;
+ for (int i = m_surfaces.size(); i; --i)
+ emit inProcessSurfaceItemClosing(m_surfaces.at(i-1));
+
+ if (m_surfaces.isEmpty()) {
+ delete m_rootObject;
+ m_rootObject = nullptr;
+ }
#endif
if (forceKill) {
@@ -236,42 +234,62 @@ void QmlInProcessRuntime::stop(bool forceKill)
void QmlInProcessRuntime::finish(int exitCode, QProcess::ExitStatus status)
{
QTimer::singleShot(0, this, [this, exitCode, status]() {
+ qCDebug(LogSystem) << "QmlInProcessRuntime (id:" << (m_app ? m_app->id() : qSL("(none)"))
+ << ") exited with code:" << exitCode << "status:" << status;
emit finished(exitCode, status);
setState(Inactive);
+#if !defined(AM_HEADLESS)
+ if (m_surfaces.isEmpty())
+ deleteLater();
+#else
deleteLater();
+#endif
});
}
#if !defined(AM_HEADLESS)
+void QmlInProcessRuntime::inProcessSurfaceItemReleased(QQuickItem *surface)
+{
+ // TODO: Take a snapshot of the last window frame and use this for potential systemUI animations.
+ // Stop the application (delete its object hierarchy) immediately and remove this workaround.
+ m_surfaces.removeOne(surface);
+ if (state() != Active && m_surfaces.isEmpty()) {
+ delete m_rootObject;
+ m_rootObject = nullptr;
+ if (state() == Inactive)
+ deleteLater();
+ }
+}
+
void QmlInProcessRuntime::onWindowClose()
{
- QQuickItem* window = reinterpret_cast<QQuickItem*>(sender()); // reinterpret_cast because the object might be broken down already!
- Q_ASSERT(window && m_windows.contains(window));
+ QQuickItem* surface = reinterpret_cast<QQuickItem*>(sender()); // reinterpret_cast because the object might be broken down already!
+ Q_ASSERT(surface && m_surfaces.contains(surface));
- emit inProcessSurfaceItemClosing(window);
+ emit inProcessSurfaceItemClosing(surface);
}
void QmlInProcessRuntime::onWindowDestroyed()
{
QObject* sndr = sender();
- m_windows.removeAll(reinterpret_cast<QQuickItem*>(sndr)); // reinterpret_cast because the object might be broken down already!
+ m_surfaces.removeAll(reinterpret_cast<QQuickItem*>(sndr)); // reinterpret_cast because the object might be broken down already!
if (m_rootObject == sndr)
m_rootObject = nullptr;
}
void QmlInProcessRuntime::onEnableFullscreen()
{
- FakeApplicationManagerWindow *window = qobject_cast<FakeApplicationManagerWindow *>(sender());
+ FakeApplicationManagerWindow *surface = qobject_cast<FakeApplicationManagerWindow *>(sender());
- emit inProcessSurfaceItemFullscreenChanging(window, true);
+ emit inProcessSurfaceItemFullscreenChanging(surface, true);
}
void QmlInProcessRuntime::onDisableFullscreen()
{
- FakeApplicationManagerWindow *window = qobject_cast<FakeApplicationManagerWindow *>(sender());
+ FakeApplicationManagerWindow *surface = qobject_cast<FakeApplicationManagerWindow *>(sender());
- emit inProcessSurfaceItemFullscreenChanging(window, false);
+ emit inProcessSurfaceItemFullscreenChanging(surface, false);
}
void QmlInProcessRuntime::addWindow(QQuickItem *window)
@@ -279,21 +297,32 @@ void QmlInProcessRuntime::addWindow(QQuickItem *window)
// Below check is only needed if the root element is a QtObject.
// It should be possible to remove this, once proper visible handling is in place.
if (state() != Inactive && state() != Shutdown) {
- if (m_windows.indexOf(window) == -1) {
- m_windows.append(window);
-
- if (auto pcw = qobject_cast<FakeApplicationManagerWindow *>(window)) {
- connect(pcw, &FakeApplicationManagerWindow::fakeFullScreenSignal, this, &QmlInProcessRuntime::onEnableFullscreen);
- connect(pcw, &FakeApplicationManagerWindow::fakeNoFullScreenSignal, this, &QmlInProcessRuntime::onDisableFullscreen);
- connect(pcw, &FakeApplicationManagerWindow::fakeCloseSignal, this, &QmlInProcessRuntime::onWindowClose);
- connect(pcw, &QObject::destroyed, this, &QmlInProcessRuntime::onWindowDestroyed);
+ auto famw = qobject_cast<FakeApplicationManagerWindow *>(window);
+ QQuickItem *surface = famw ? famw->m_surfaceItem : window;
+
+ if (!m_surfaces.contains(surface)) {
+ if (famw) {
+ surface = new InProcessSurfaceItem(famw);
+ connect(famw, &FakeApplicationManagerWindow::fakeFullScreenSignal, this, &QmlInProcessRuntime::onEnableFullscreen);
+ connect(famw, &FakeApplicationManagerWindow::fakeNoFullScreenSignal, this, &QmlInProcessRuntime::onDisableFullscreen);
+ connect(famw, &FakeApplicationManagerWindow::fakeCloseSignal, this, &QmlInProcessRuntime::onWindowClose);
+ connect(famw, &QObject::destroyed, this, &QmlInProcessRuntime::onWindowDestroyed);
}
+ m_surfaces.append(surface);
}
- emit inProcessSurfaceItemReady(window);
+ emit inProcessSurfaceItemReady(surface);
}
}
+void QmlInProcessRuntime::removeWindow(QQuickItem *window)
+{
+ auto famw = qobject_cast<FakeApplicationManagerWindow *>(window);
+ QQuickItem *surface = famw ? famw->m_surfaceItem : window;
+ if (m_surfaces.removeOne(surface))
+ emit inProcessSurfaceItemClosing(surface);
+}
+
#endif // !AM_HEADLESS
void QmlInProcessRuntime::openDocument(const QString &document, const QString &mimeType)
diff --git a/src/manager-lib/qmlinprocessruntime.h b/src/manager-lib/qmlinprocessruntime.h
index 91ac932b..6e8208c2 100644
--- a/src/manager-lib/qmlinprocessruntime.h
+++ b/src/manager-lib/qmlinprocessruntime.h
@@ -79,6 +79,9 @@ public:
public slots:
bool start() override;
void stop(bool forceKill = false) override;
+#if !defined(AM_HEADLESS)
+ void inProcessSurfaceItemReleased(QQuickItem *window) override;
+#endif
signals:
void aboutToStop(); // used for the ApplicationInterface
@@ -94,15 +97,19 @@ private slots:
void finish(int exitCode, QProcess::ExitStatus status);
private:
+ static const char *s_runtimeKey;
+
QString m_document;
QmlInProcessApplicationInterface *m_applicationIf = nullptr;
+ bool m_componentError;
#if !defined(AM_HEADLESS)
// used by FakeApplicationManagerWindow to register windows
void addWindow(QQuickItem *window);
+ void removeWindow(QQuickItem *window);
QObject *m_rootObject = nullptr;
- QList<QQuickItem *> m_windows;
+ QList<QQuickItem *> m_surfaces;
friend class FakeApplicationManagerWindow; // for emitting signals on behalf of this class in onComplete
#endif
diff --git a/src/window-lib/inprocesswindow.cpp b/src/window-lib/inprocesswindow.cpp
index 94bb2839..4a508bab 100644
--- a/src/window-lib/inprocesswindow.cpp
+++ b/src/window-lib/inprocesswindow.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "inprocesswindow.h"
+#include "inprocesssurfaceitem.h"
QT_BEGIN_NAMESPACE_AM
@@ -62,38 +63,44 @@ static bool isName(const QByteArray &key)
InProcessWindow::InProcessWindow(const Application *app, QQuickItem *surfaceItem)
: Window(app, surfaceItem)
{
- surfaceItem->installEventFilter(this);
+ auto ipsi = qobject_cast<InProcessSurfaceItem *>(surfaceItem);
+ if (ipsi)
+ m_windowProperties = ipsi->windowProperties();
+ else
+ m_windowProperties.reset(new QObject());
+
+ m_windowProperties->installEventFilter(this);
}
bool InProcessWindow::setWindowProperty(const QString &name, const QVariant &value)
{
QByteArray key = nameToKey(name);
- QVariant oldValue = windowItem()->property(key);
+ QVariant oldValue = m_windowProperties->property(key);
bool changed = !oldValue.isValid() || (oldValue != value);
- if (changed) {
- windowItem()->setProperty(key, value);
- }
+ if (changed)
+ m_windowProperties->setProperty(key, value);
+
return true;
}
QVariant InProcessWindow::windowProperty(const QString &name) const
{
QByteArray key = nameToKey(name);
- return windowItem()->property(key);
+ return m_windowProperties->property(key);
}
QVariantMap InProcessWindow::windowProperties() const
{
- const QList<QByteArray> keys = windowItem()->dynamicPropertyNames();
+ const QList<QByteArray> keys = m_windowProperties->dynamicPropertyNames();
QVariantMap map;
for (const QByteArray &key : keys) {
if (!isName(key))
continue;
- QString name = QString::fromUtf8(key.mid(4));
- map[name] = windowItem()->property(key);
+ QString name = keyToName(key);
+ map[name] = m_windowProperties->property(key);
}
return map;
@@ -101,15 +108,13 @@ QVariantMap InProcessWindow::windowProperties() const
bool InProcessWindow::eventFilter(QObject *o, QEvent *e)
{
- if ((o == windowItem()) && (e->type() == QEvent::DynamicPropertyChange)) {
+ if ((o == m_windowProperties) && (e->type() == QEvent::DynamicPropertyChange)) {
QDynamicPropertyChangeEvent *dpce = static_cast<QDynamicPropertyChangeEvent *>(e);
QByteArray key = dpce->propertyName();
if (isName(key)) {
QString name = keyToName(dpce->propertyName());
- emit windowPropertyChanged(name, windowItem()->property(key));
-
- //qWarning() << "IPW: got change" << name << " --> " << surfaceItem()->property(key).toString();
+ emit windowPropertyChanged(name, m_windowProperties->property(key));
}
}
diff --git a/src/window-lib/inprocesswindow.h b/src/window-lib/inprocesswindow.h
index dba21d60..c5e0f92c 100644
--- a/src/window-lib/inprocesswindow.h
+++ b/src/window-lib/inprocesswindow.h
@@ -57,8 +57,6 @@ public:
bool isInProcess() const override { return true; }
- //bool isClosing() const override;
-
bool setWindowProperty(const QString &name, const QVariant &value) override;
QVariant windowProperty(const QString &name) const override;
QVariantMap windowProperties() const override;
@@ -67,7 +65,7 @@ protected:
bool eventFilter(QObject *o, QEvent *e) override;
private:
- QVariantMap m_windowProperties;
+ QSharedPointer<QObject> m_windowProperties;
};
QT_END_NAMESPACE_AM
diff --git a/src/window-lib/windowmanager.cpp b/src/window-lib/windowmanager.cpp
index 6c31cc31..989bf8b9 100644
--- a/src/window-lib/windowmanager.cpp
+++ b/src/window-lib/windowmanager.cpp
@@ -593,6 +593,8 @@ void WindowManager::setupInProcessRuntime(AbstractRuntime *runtime)
this, static_cast<void (WindowManager::*)(QQuickItem *)>(&WindowManager::inProcessSurfaceItemCreated), Qt::QueuedConnection);
connect(runtime, &AbstractRuntime::inProcessSurfaceItemClosing,
this, static_cast<void (WindowManager::*)(QQuickItem *)>(&WindowManager::inProcessSurfaceItemClosing), Qt::QueuedConnection);
+ connect(this, &WindowManager::windowReleased, runtime,
+ &AbstractRuntime::inProcessSurfaceItemReleased, Qt::QueuedConnection);
}
}
@@ -619,10 +621,13 @@ void WindowManager::releaseWindow(QQuickItem *window)
qCWarning(LogGraphics) << "releaseWindow was called with an invalid window pointer" << window;
return;
}
+
Window *win = d->windows.at(index);
if (!win)
return;
+ emit windowReleased(window);
+
beginRemoveRows(QModelIndex(), index, index);
d->windows.removeAt(index);
endRemoveRows();
diff --git a/src/window-lib/windowmanager.h b/src/window-lib/windowmanager.h
index 7ba30704..a9c5f8fa 100644
--- a/src/window-lib/windowmanager.h
+++ b/src/window-lib/windowmanager.h
@@ -113,6 +113,8 @@ signals:
void windowClosing(int index, QQuickItem *window);
void windowLost(int index, QQuickItem *window);
+ void windowReleased(QQuickItem *window);
+
void windowPropertyChanged(QQuickItem *window, const QString &name, const QVariant &value);
void compositorViewRegistered(QQuickWindow *view);
diff --git a/tests/qml/fakeamwindow/am-config.yaml b/tests/qml/fakeamwindow/am-config.yaml
new file mode 100644
index 00000000..7ea683dd
--- /dev/null
+++ b/tests/qml/fakeamwindow/am-config.yaml
@@ -0,0 +1,15 @@
+formatVersion: 1
+formatType: am-configuration
+---
+applications:
+ builtinAppsManifestDir: "${CONFIG_PWD}/apps"
+ installedAppsManifestDir: "/tmp/am-famw-test/manifests"
+ appImageMountDir: "/tmp/am-famw-test/image-mounts"
+ database: "/tmp/am-famw-test/apps.db"
+
+installationLocations:
+- id: "internal-0"
+ installationPath: "/tmp/am-famw-test/apps"
+ documentPath: "/tmp/am-famw-test/docs"
+ mountPoint: "/tmp"
+ isDefault: true
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent1/icon.png b/tests/qml/fakeamwindow/apps/test.famw.parent1/icon.png
new file mode 100644
index 00000000..c1397153
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent1/icon.png
Binary files differ
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent1/info.yaml b/tests/qml/fakeamwindow/apps/test.famw.parent1/info.yaml
new file mode 100644
index 00000000..6c77b8d4
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent1/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'test.famw.parent1'
+icon: 'icon.png'
+code: 'parent1.qml'
+runtime: 'qml'
+name:
+ en: 'FakeApplicationManagerWindow onParentChanged'
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent1/parent1.qml b/tests/qml/fakeamwindow/apps/test.famw.parent1/parent1.qml
new file mode 100644
index 00000000..87dccf3b
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent1/parent1.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ onParentChanged: console.log("Impossible");
+}
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent2/icon.png b/tests/qml/fakeamwindow/apps/test.famw.parent2/icon.png
new file mode 100644
index 00000000..c1397153
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent2/icon.png
Binary files differ
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent2/info.yaml b/tests/qml/fakeamwindow/apps/test.famw.parent2/info.yaml
new file mode 100644
index 00000000..f5ebf781
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent2/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'test.famw.parent2'
+icon: 'icon.png'
+code: 'parent2.qml'
+runtime: 'qml'
+name:
+ en: 'FakeApplicationManagerWindow parent property'
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent2/parent2.qml b/tests/qml/fakeamwindow/apps/test.famw.parent2/parent2.qml
new file mode 100644
index 00000000..dbd96c6d
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent2/parent2.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ id: root
+
+ Item {
+ id: container
+ }
+
+ Connections {
+ target: ApplicationInterface
+ onOpenDocument: {
+ if (documentUrl === 'set')
+ root.parent = container;
+ }
+ }
+
+ Component.onCompleted: console.warn("The parent is: " + root.parent);
+}
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent3/Test.qml b/tests/qml/fakeamwindow/apps/test.famw.parent3/Test.qml
new file mode 100644
index 00000000..87dccf3b
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent3/Test.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ onParentChanged: console.log("Impossible");
+}
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent3/icon.png b/tests/qml/fakeamwindow/apps/test.famw.parent3/icon.png
new file mode 100644
index 00000000..c1397153
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent3/icon.png
Binary files differ
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent3/info.yaml b/tests/qml/fakeamwindow/apps/test.famw.parent3/info.yaml
new file mode 100644
index 00000000..ec5292d7
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent3/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'test.famw.parent3'
+icon: 'icon.png'
+code: 'parent3.qml'
+runtime: 'qml'
+name:
+ en: 'Dynamically loaded FakeApplicationManagerWindow'
diff --git a/tests/qml/fakeamwindow/apps/test.famw.parent3/parent3.qml b/tests/qml/fakeamwindow/apps/test.famw.parent3/parent3.qml
new file mode 100644
index 00000000..b20f1bfa
--- /dev/null
+++ b/tests/qml/fakeamwindow/apps/test.famw.parent3/parent3.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ id: root
+
+ Loader {
+ id: ldr
+ }
+
+ Connections {
+ target: ApplicationInterface
+ onOpenDocument: {
+ if (documentUrl === "load")
+ ldr.source = "Test.qml";
+ }
+ }
+}
diff --git a/tests/qml/fakeamwindow/fakeamwindow.pro b/tests/qml/fakeamwindow/fakeamwindow.pro
new file mode 100644
index 00000000..9b7501a2
--- /dev/null
+++ b/tests/qml/fakeamwindow/fakeamwindow.pro
@@ -0,0 +1,4 @@
+AM_CONFIG = am-config.yaml
+TEST_FILES = tst_fakeamwindow.qml
+
+load(am-qml-testcase)
diff --git a/tests/qml/fakeamwindow/tst_fakeamwindow.qml b/tests/qml/fakeamwindow/tst_fakeamwindow.qml
new file mode 100644
index 00000000..a127852b
--- /dev/null
+++ b/tests/qml/fakeamwindow/tst_fakeamwindow.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.3
+import QtTest 1.0
+import QtApplicationManager 1.0
+
+Item {
+ TestCase {
+ name: "Dummy" // workaround to make actual test below optional
+ when: windowShown
+
+ function test_dummy() {}
+ }
+
+ TestCase {
+ name: "FakeApplicationManagerWindow"
+ when: ApplicationManager.singleProcess
+ optional: true
+
+ function test_parent1() {
+ ignoreWarning('QML ApplicationManagerWindow: Cannot assign to non-existent property "onParentChanged"');
+ ApplicationManager.startApplication("test.famw.parent1");
+ }
+
+ function test_parent2() {
+ ignoreWarning('The parent is: undefined');
+ ApplicationManager.startApplication("test.famw.parent2");
+ wait(0);
+ ignoreWarning('TypeError: Cannot assign to read-only property "parent"');
+ ApplicationManager.startApplication("test.famw.parent2", "set");
+ }
+
+ function test_parent3() {
+ ApplicationManager.startApplication("test.famw.parent3");
+ wait(0);
+ ignoreWarning('QML ApplicationManagerWindow: Cannot assign to non-existent property "onParentChanged"');
+ ApplicationManager.startApplication("test.famw.parent3", "load");
+ }
+ }
+}
diff --git a/tests/qml/qml.pro b/tests/qml/qml.pro
index 968ead34..906bde2c 100644
--- a/tests/qml/qml.pro
+++ b/tests/qml/qml.pro
@@ -1,4 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = \
simple \
- windowmapping
+ windowmapping \
+ fakeamwindow
diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml b/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml
new file mode 100644
index 00000000..2d65b8ea
--- /dev/null
+++ b/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ Component.onCompleted: setWindowProperty("type", "sub");
+}
diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/icon.png b/tests/qml/windowmapping/apps/test.winmap.loader/icon.png
new file mode 100644
index 00000000..c1397153
--- /dev/null
+++ b/tests/qml/windowmapping/apps/test.winmap.loader/icon.png
Binary files differ
diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/info.yaml b/tests/qml/windowmapping/apps/test.winmap.loader/info.yaml
new file mode 100644
index 00000000..6e486078
--- /dev/null
+++ b/tests/qml/windowmapping/apps/test.winmap.loader/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'test.winmap.loader'
+icon: 'icon.png'
+code: 'loader.qml'
+runtime: 'qml'
+name:
+ en: 'Dynamic loading'
diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml b/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml
new file mode 100644
index 00000000..5d09e43f
--- /dev/null
+++ b/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager 1.0
+
+ApplicationManagerWindow {
+ id: root
+ visible: true
+
+ Loader {
+ id: ldr
+ active: false
+ source: "SubWin.qml"
+ }
+
+ Connections {
+ target: ApplicationInterface
+ onOpenDocument: {
+ switch (documentUrl) {
+ case "show-sub": ldr.active = true; break;
+ case "hide-sub": ldr.active = false; break;
+ }
+ }
+ }
+}
diff --git a/tests/qml/windowmapping/tst_windowmapping.qml b/tests/qml/windowmapping/tst_windowmapping.qml
index 606a2f6b..0ea7a81c 100644
--- a/tests/qml/windowmapping/tst_windowmapping.qml
+++ b/tests/qml/windowmapping/tst_windowmapping.qml
@@ -92,85 +92,40 @@ TestCase {
}
}
- function test_default_data() {
- return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" },
- // skipping QtObject, as it doesn't show anything
- { tag: "Rectangle", appId: "test.winmap.rectangle" },
- { tag: "Window", appId: "test.winmap.window" } ];
- }
-
- function test_default(data) {
- if (ApplicationManager.singleProcess && data.tag === "Window")
- skip("Window root element is not properly supported in single process mode.");
+ function test_amwin_advanced() {
+ var appId = "test.winmap.amwin2";
+ ApplicationManager.startApplication(appId, "show-sub");
+ wait(2000);
+ compare(windowReadySpy.count, 0);
- var appId = data.appId;
- compare(chrome.children.length, 1);
- ApplicationManager.startApplication(appId);
- windowReadySpy.wait(2000);
- compare(windowReadySpy.count, 1);
+ ApplicationManager.startApplication(appId, "show-main");
+ windowReadySpy.wait(3000);
+ compare(windowReadySpy.count, 2);
windowReadySpy.clear();
- compare(chrome.children.length, 2);
ApplicationManager.stopApplication(appId);
- windowLostSpy.wait(2000);
- compare(windowLostSpy.count, 1);
+ ensureAppTerminated(appId);
windowLostSpy.clear();
-        ensureAppTerminated(appId);
}
- function test_mapping_data() {
- return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" },
- { tag: "QtObject", appId: "test.winmap.qtobject" },
- { tag: "Rectangle", appId: "test.winmap.rectangle" },
- { tag: "Window", appId: "test.winmap.window" } ];
- }
-
- function test_mapping(data) {
- if (ApplicationManager.singleProcess && data.tag === "Window")
- skip("Window root element is not properly supported in single process mode.");
-
- var appId = data.appId;
- compare(chrome.children.length, 1);
- ApplicationManager.startApplication(appId, "show-main");
- windowReadySpy.wait(2000);
- compare(windowReadySpy.count, 1);
- windowReadySpy.clear();
- compare(chrome.children.length, 2);
+ function test_amwin_loader() {
+ if (!ApplicationManager.singleProcess)
+ skip("Sporadically crashes in QtWaylandClient::QWaylandDisplay::flushRequests()");
- compare(subChrome.children.length, 0);
+ var appId = "test.winmap.loader";
ApplicationManager.startApplication(appId, "show-sub");
- windowReadySpy.wait(2000);
- compare(windowReadySpy.count, 1);
+ windowReadySpy.wait(3000);
+ compare(windowReadySpy.count, 2);
windowReadySpy.clear();
- compare(subChrome.children.length, 1);
- var openWindows = 2;
- // visible handling needs to be fixed for single process mode (AUTOSUITE-131):
- if (!ApplicationManager.singleProcess) {
- ApplicationManager.startApplication(appId, "hide-sub");
- windowLostSpy.wait(2000);
- compare(windowLostSpy.count, 1);
- windowLostSpy.clear();
- openWindows = 1;
- compare(subChrome.children.length, 0);
- }
-
- ApplicationManager.stopApplication(appId);
+ ApplicationManager.startApplication(appId, "hide-sub");
windowLostSpy.wait(2000);
- compare(windowLostSpy.count, openWindows);
+ compare(windowLostSpy.count, 1);
windowLostSpy.clear();
- ensureAppTerminated(appId);
- }
- function test_amwin_advanced() {
- var appId = "test.winmap.amwin2";
ApplicationManager.startApplication(appId, "show-sub");
- wait(2000);
- compare(windowReadySpy.count, 0);
-
- ApplicationManager.startApplication(appId, "show-main");
windowReadySpy.wait(3000);
- compare(windowReadySpy.count, 2);
+ compare(windowReadySpy.count, 1);
windowReadySpy.clear();
ApplicationManager.stopApplication(appId);
@@ -232,4 +187,74 @@ TestCase {
ensureAppTerminated(appId);
windowLostSpy.clear();
}
+
+ function test_default_data() {
+ return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" },
+ // skipping QtObject, as it doesn't show anything
+ { tag: "Rectangle", appId: "test.winmap.rectangle" },
+ { tag: "Window", appId: "test.winmap.window" } ];
+ }
+
+ function test_default(data) {
+ if (ApplicationManager.singleProcess && data.tag === "Window")
+ skip("Window root element is not properly supported in single process mode.");
+
+ var appId = data.appId;
+ compare(chrome.children.length, 1);
+ ApplicationManager.startApplication(appId);
+ windowReadySpy.wait(2000);
+ compare(windowReadySpy.count, 1);
+ windowReadySpy.clear();
+ compare(chrome.children.length, 2);
+
+ ApplicationManager.stopApplication(appId);
+ windowLostSpy.wait(2000);
+ compare(windowLostSpy.count, 1);
+ windowLostSpy.clear();
+        ensureAppTerminated(appId);
+ }
+
+ function test_mapping_data() {
+ return [ { tag: "ApplicationManagerWindow", appId: "test.winmap.amwin" },
+ { tag: "QtObject", appId: "test.winmap.qtobject" },
+ { tag: "Rectangle", appId: "test.winmap.rectangle" },
+ { tag: "Window", appId: "test.winmap.window" } ];
+ }
+
+ function test_mapping(data) {
+ if (ApplicationManager.singleProcess && data.tag === "Window")
+ skip("Window root element is not properly supported in single process mode.");
+
+ var appId = data.appId;
+ compare(chrome.children.length, 1);
+ ApplicationManager.startApplication(appId, "show-main");
+ windowReadySpy.wait(2000);
+ compare(windowReadySpy.count, 1);
+ windowReadySpy.clear();
+ compare(chrome.children.length, 2);
+
+ compare(subChrome.children.length, 0);
+ ApplicationManager.startApplication(appId, "show-sub");
+ windowReadySpy.wait(2000);
+ compare(windowReadySpy.count, 1);
+ windowReadySpy.clear();
+ compare(subChrome.children.length, 1);
+
+ var openWindows = 2;
+ // visible handling needs to be fixed for single process mode (AUTOSUITE-131):
+ if (!ApplicationManager.singleProcess) {
+ ApplicationManager.startApplication(appId, "hide-sub");
+ windowLostSpy.wait(2000);
+ compare(windowLostSpy.count, 1);
+ windowLostSpy.clear();
+ openWindows = 1;
+ compare(subChrome.children.length, 0);
+ }
+
+ ApplicationManager.stopApplication(appId);
+ windowLostSpy.wait(2000);
+ compare(windowLostSpy.count, openWindows);
+ windowLostSpy.clear();
+ ensureAppTerminated(appId);
+ }
}