summaryrefslogtreecommitdiffstats
path: root/src/webengine/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/webengine/api')
-rw-r--r--src/webengine/api/qquickwebengineview.cpp84
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h16
2 files changed, 97 insertions, 3 deletions
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index e9375148e..d159ed8fc 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -47,6 +47,7 @@
#include <QScreen>
#include <QUrl>
+#include <QQmlEngine>
QT_BEGIN_NAMESPACE
@@ -158,9 +159,48 @@ void QQuickWebEngineViewPrivate::focusContainer()
void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, const QRect &)
{
- Q_UNUSED(newWebContents);
- Q_UNUSED(disposition);
- Q_UNREACHABLE();
+ Q_Q(QQuickWebEngineView);
+ QQmlEngine *engine = QtQml::qmlEngine(q);
+ // This is currently only supported for QML instantiated WebEngineViews.
+ // We could emit a QObject* and set JavaScriptOwnership explicitly on it
+ // but this would make the signal cumbersome to use in C++ where one, and
+ // only one, of the connected slots would have to destroy the given handle.
+ // A virtual method instead of a signal would work better in this case.
+ if (!engine)
+ return;
+ static const QMetaMethod createWindowSignal = QMetaMethod::fromSignal(&QQuickWebEngineViewExperimental::createWindow);
+ if (!e->isSignalConnected(createWindowSignal))
+ return;
+
+ QQuickWebEngineViewHandle *handle = new QQuickWebEngineViewHandle;
+ // This increases the ref-count of newWebContents and will tell Chromium
+ // to start loading it and possibly return it to its parent page window.open().
+ handle->adapter = newWebContents;
+ // Clearly mark our wrapper as owned by JavaScript, we then depend on it
+ // being adopted or else eventually cleaned up by the GC.
+ QJSValue jsHandle = engine->newQObject(handle);
+
+ QString dispositionString;
+ switch (disposition) {
+ case WebContentsAdapterClient::NewForegroundTabDisposition:
+ case WebContentsAdapterClient::NewBackgroundTabDisposition:
+ dispositionString = QStringLiteral("tab");
+ break;
+ case WebContentsAdapterClient::NewPopupDisposition:
+ dispositionString = QStringLiteral("popup");
+ break;
+ case WebContentsAdapterClient::NewWindowDisposition:
+ dispositionString = QStringLiteral("window");
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ emit e->createWindow(jsHandle, dispositionString);
+
+ // We currently require the adoption to happen within the signal handler to avoid having
+ // to support a null WebContentsAdapterClient for too long after having returned.
+ handle->adapter.reset();
}
void QQuickWebEngineViewPrivate::close()
@@ -285,6 +325,14 @@ void QQuickWebEngineView::geometryChanged(const QRectF &newGeometry, const QRect
}
}
+QQuickWebEngineViewHandle::QQuickWebEngineViewHandle()
+{
+}
+
+QQuickWebEngineViewHandle::~QQuickWebEngineViewHandle()
+{
+}
+
QQuickWebEngineViewExperimental::QQuickWebEngineViewExperimental(QQuickWebEngineViewPrivate *viewPrivate)
: q_ptr(0)
, d_ptr(viewPrivate)
@@ -320,4 +368,34 @@ void QQuickWebEngineViewport::setDevicePixelRatio(qreal devicePixelRatio)
Q_EMIT devicePixelRatioChanged();
}
+void QQuickWebEngineViewExperimental::adoptHandle(QQuickWebEngineViewHandle *viewHandle)
+{
+ if (!viewHandle || !viewHandle->adapter) {
+ qWarning("Trying to adopt an empty handle, it was either already adopted or was invalidated."
+ "\nYou must do the adoption synchronously within the createWindow signal handler."
+ " If the handle hasn't been adopted before returning, it will be invalidated.");
+ return;
+ }
+
+ Q_Q(QQuickWebEngineView);
+ Q_D(QQuickWebEngineView);
+
+ // This throws away the WebContentsAdapter that has been used until now.
+ // All its states, particularly the loading URL, are replaced by the adopted WebContentsAdapter.
+ d->adapter = viewHandle->adapter;
+ viewHandle->adapter.reset();
+
+ d->adapter->initialize(d);
+
+ // Emit signals for values that might be different from the previous WebContentsAdapter.
+ emit q->titleChanged();
+ emit q->urlChanged();
+ emit q->iconChanged();
+ emit q->loadingStateChanged();
+ emit q->loadProgressChanged();
+}
+
QT_END_NAMESPACE
+
+#include "moc_qquickwebengineview_p.cpp"
+#include "moc_qquickwebengineview_p_p.cpp"
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index b356b8881..0af1dcb45 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -71,11 +71,27 @@ private:
Q_DECLARE_PRIVATE(QQuickWebEngineView)
};
+class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewHandle : public QObject {
+ Q_OBJECT
+public:
+ QQuickWebEngineViewHandle();
+ ~QQuickWebEngineViewHandle();
+
+private:
+ QExplicitlySharedDataPointer<WebContentsAdapter> adapter;
+ friend class QQuickWebEngineViewExperimental;
+ friend class QQuickWebEngineViewPrivate;
+};
+
class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewExperimental : public QObject {
Q_OBJECT
Q_PROPERTY(QQuickWebEngineViewport *viewport READ viewport)
public:
QQuickWebEngineViewport *viewport() const;
+ Q_INVOKABLE void adoptHandle(QQuickWebEngineViewHandle *viewHandle);
+
+Q_SIGNALS:
+ void createWindow(const QJSValue &newViewHandle, const QString &newViewDisposition);
private:
QQuickWebEngineViewExperimental(QQuickWebEngineViewPrivate* viewPrivate);