diff options
-rw-r--r-- | examples/quick/quicknanobrowser/quickwindow.qml | 39 | ||||
-rw-r--r-- | src/webengine/api/qquickwebenginenewviewrequest.cpp | 71 | ||||
-rw-r--r-- | src/webengine/api/qquickwebenginenewviewrequest_p.h | 75 | ||||
-rw-r--r-- | src/webengine/api/qquickwebengineview.cpp | 103 | ||||
-rw-r--r-- | src/webengine/api/qquickwebengineview_p.h | 7 | ||||
-rw-r--r-- | src/webengine/api/qquickwebengineview_p_p.h | 17 | ||||
-rw-r--r-- | src/webengine/plugin/plugin.cpp | 2 | ||||
-rw-r--r-- | src/webengine/webengine.pro | 2 |
8 files changed, 215 insertions, 101 deletions
diff --git a/examples/quick/quicknanobrowser/quickwindow.qml b/examples/quick/quicknanobrowser/quickwindow.qml index d72c30021..4b708ffed 100644 --- a/examples/quick/quicknanobrowser/quickwindow.qml +++ b/examples/quick/quicknanobrowser/quickwindow.qml @@ -49,8 +49,8 @@ import QtQuick.Controls.Private 1.0 ApplicationWindow { id: browserWindow - function load(url) { tabs.currentView.url = url } - function adoptHandle(viewHandle) { tabs.currentView.adoptHandle(viewHandle) } + function load(url) { currentWebView.url = url } + property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null property bool isFullScreen: visibility == Window.FullScreen onIsFullScreenChanged: { @@ -62,7 +62,7 @@ ApplicationWindow { height: 600 width: 800 visible: true - title: tabs.currentView && tabs.currentView.title + title: currentWebView && currentWebView.title // Make sure the Qt.WindowFullscreenButtonHint is set on Mac. Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint @@ -118,21 +118,21 @@ ApplicationWindow { ToolButton { id: backButton iconSource: "icons/go-previous.png" - onClicked: tabs.currentView.goBack() - enabled: tabs.currentView && tabs.currentView.canGoBack + onClicked: currentWebView.goBack() + enabled: currentWebView && currentWebView.canGoBack activeFocusOnTab: !browserWindow.platformIsMac } ToolButton { id: forwardButton iconSource: "icons/go-next.png" - onClicked: tabs.currentView.goForward() - enabled: tabs.currentView && tabs.currentView.canGoForward + onClicked: currentWebView.goForward() + enabled: currentWebView && currentWebView.canGoForward activeFocusOnTab: !browserWindow.platformIsMac } ToolButton { id: reloadButton - iconSource: tabs.currentView && tabs.currentView.loading ? "icons/process-stop.png" : "icons/view-refresh.png" - onClicked: tabs.currentView && tabs.currentView.loading ? tabs.currentView.stop() : tabs.currentView.reload() + iconSource: currentWebView && currentWebView.loading ? "icons/process-stop.png" : "icons/view-refresh.png" + onClicked: currentWebView && currentWebView.loading ? currentWebView.stop() : currentWebView.reload() activeFocusOnTab: !browserWindow.platformIsMac } TextField { @@ -143,7 +143,7 @@ ApplicationWindow { z: 2 id: faviconImage width: 16; height: 16 - source: tabs.currentView && tabs.currentView.icon + source: currentWebView && currentWebView.icon } style: TextFieldStyle { padding { @@ -152,8 +152,8 @@ ApplicationWindow { } focus: true Layout.fillWidth: true - text: tabs.currentView && tabs.currentView.url - onAccepted: tabs.currentView.url = utils.fromUserInput(text) + text: currentWebView && currentWebView.url + onAccepted: currentWebView.url = utils.fromUserInput(text) } } ProgressBar { @@ -172,13 +172,12 @@ ApplicationWindow { z: -2; minimumValue: 0 maximumValue: 100 - value: (tabs.currentView && tabs.currentView.loadProgress < 100) ? tabs.currentView.loadProgress : 0 + value: (currentWebView && currentWebView.loadProgress < 100) ? currentWebView.loadProgress : 0 } } TabView { id: tabs - property Item currentView: currentIndex < count ? getTab(currentIndex).item : null function createEmptyTab() { var tab = addTab("", tabComponent) // We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately. @@ -225,16 +224,16 @@ ApplicationWindow { } } - onCreateWindow: { - if (newViewDisposition == "popup") - print("Warning: Ignored a popup window.") - else if (newViewDisposition == "tab") { + onNewViewRequested: { + if (request.popup) + print("Warning: Blocked a popup window.") + else if (request.destination == WebEngineView.NewViewInTab) { var tab = tabs.createEmptyTab() - tab.item.adoptHandle(newViewHandle) + request.openIn(tab.item) } else { var component = Qt.createComponent("quickwindow.qml") var window = component.createObject() - window.adoptHandle(newViewHandle) + request.openIn(window.currentWebView) } } extraContextMenuEntriesComponent: ContextMenuExtras {} diff --git a/src/webengine/api/qquickwebenginenewviewrequest.cpp b/src/webengine/api/qquickwebenginenewviewrequest.cpp new file mode 100644 index 000000000..8af8f5b49 --- /dev/null +++ b/src/webengine/api/qquickwebenginenewviewrequest.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickwebenginenewviewrequest_p.h" + +#include "qquickwebengineview_p_p.h" +#include "web_contents_adapter.h" + +QQuickWebEngineNewViewRequest::QQuickWebEngineNewViewRequest() +{ +} + +QQuickWebEngineNewViewRequest::~QQuickWebEngineNewViewRequest() +{ +} + +QQuickWebEngineView::NewViewDestination QQuickWebEngineNewViewRequest::destination() const +{ + return m_destination; +} + +bool QQuickWebEngineNewViewRequest::isPopup() const +{ + return m_isPopup; +} + +void QQuickWebEngineNewViewRequest::openIn(QQuickWebEngineView *view) +{ + if (view) { + view->d_func()->adoptWebContents(m_adapter.data()); + m_adapter.reset(); + } +} diff --git a/src/webengine/api/qquickwebenginenewviewrequest_p.h b/src/webengine/api/qquickwebenginenewviewrequest_p.h new file mode 100644 index 000000000..ed762cd39 --- /dev/null +++ b/src/webengine/api/qquickwebenginenewviewrequest_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINENEWVIEWREQUEST_P_H +#define QQUICKWEBENGINENEWVIEWREQUEST_P_H + +#include "qtwebengineglobal_p.h" +#include "qquickwebengineview_p.h" + +class WebContentsAdapter; + +QT_BEGIN_NAMESPACE + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineNewViewRequest : public QObject { + Q_OBJECT + Q_PROPERTY(QQuickWebEngineView::NewViewDestination destination READ destination CONSTANT FINAL) + Q_PROPERTY(bool popup READ isPopup CONSTANT FINAL) +public: + ~QQuickWebEngineNewViewRequest(); + + QQuickWebEngineView::NewViewDestination destination() const; + bool isPopup() const; + Q_INVOKABLE void openIn(QQuickWebEngineView *view); + +private: + QQuickWebEngineNewViewRequest(); + QQuickWebEngineView::NewViewDestination m_destination; + bool m_isPopup; + QExplicitlySharedDataPointer<WebContentsAdapter> m_adapter; + friend class QQuickWebEngineViewPrivate; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickWebEngineNewViewRequest) + +#endif // QQUICKWEBENGINENEWVIEWREQUEST_P_H diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 6693c8c79..727b5661b 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -44,6 +44,7 @@ #include "javascript_dialog_controller.h" #include "qquickwebengineloadrequest_p.h" +#include "qquickwebenginenewviewrequest_p.h" #include "render_widget_host_view_qt_delegate_quick.h" #include "ui_delegates_manager.h" #include "web_contents_adapter.h" @@ -280,48 +281,28 @@ void QQuickWebEngineViewPrivate::focusContainer() void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, const QRect &) { - 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; + QQuickWebEngineNewViewRequest request; // 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); + request.m_adapter = newWebContents; + request.m_isPopup = false; - QString dispositionString; switch (disposition) { + case WebContentsAdapterClient::NewPopupDisposition: + request.m_isPopup = true; + // fall through case WebContentsAdapterClient::NewForegroundTabDisposition: case WebContentsAdapterClient::NewBackgroundTabDisposition: - dispositionString = QStringLiteral("tab"); - break; - case WebContentsAdapterClient::NewPopupDisposition: - dispositionString = QStringLiteral("popup"); + request.m_destination = QQuickWebEngineView::NewViewInTab; break; case WebContentsAdapterClient::NewWindowDisposition: - dispositionString = QStringLiteral("window"); + request.m_destination = QQuickWebEngineView::NewViewInWindow; 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(); + emit e->newViewRequested(&request); } void QQuickWebEngineViewPrivate::close() @@ -353,6 +334,32 @@ void QQuickWebEngineViewPrivate::setDevicePixelRatio(qreal devicePixelRatio) m_dpiScale = devicePixelRatio / screen->devicePixelRatio(); } +void QQuickWebEngineViewPrivate::adoptWebContents(WebContentsAdapter *webContents) +{ + if (!webContents) { + qWarning("Trying to open an empty request, it was either already used or was invalidated." + "\nYou must complete the request synchronously within the newViewRequested signal handler." + " If a view hasn't been adopted before returning, the request will be invalidated."); + return; + } + + Q_Q(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. + adapter = webContents; + adapter->initialize(this); + + // Emit signals for values that might be different from the previous WebContentsAdapter. + emit q->titleChanged(); + emit q->urlChanged(); + emit q->iconChanged(); + // FIXME: The current loading state should be stored in the WebContentAdapter + // and it should be checked here if the signal emission is really necessary. + QQuickWebEngineLoadRequest loadRequest(adapter->activeUrl(), QQuickWebEngineView::LoadSucceededStatus); + emit q->loadingStateChanged(&loadRequest); + emit q->loadProgressChanged(); +} + QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent) : QQuickItem(*(new QQuickWebEngineViewPrivate), parent) { @@ -509,14 +516,6 @@ void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &va QQuickItem::itemChange(change, value); } -QQuickWebEngineViewHandle::QQuickWebEngineViewHandle() -{ -} - -QQuickWebEngineViewHandle::~QQuickWebEngineViewHandle() -{ -} - QQuickWebEngineViewExperimental::QQuickWebEngineViewExperimental(QQuickWebEngineViewPrivate *viewPrivate) : q_ptr(0) , d_ptr(viewPrivate) @@ -552,36 +551,6 @@ 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(); - // FIXME: The current loading state should be stored in the WebContentAdapter - // and it should be checked here if the signal emission is really necessary. - QQuickWebEngineLoadRequest loadRequest(d->adapter->activeUrl(), QQuickWebEngineView::LoadSucceededStatus); - emit q->loadingStateChanged(&loadRequest); - emit q->loadProgressChanged(); -} - QT_END_NAMESPACE #include "moc_qquickwebengineview_p.cpp" diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 77d5b9828..66dc37622 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -62,6 +62,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_PROPERTY(bool inspectable READ inspectable WRITE setInspectable) Q_ENUMS(LoadStatus); Q_ENUMS(ErrorDomain); + Q_ENUMS(NewViewDestination); public: QQuickWebEngineView(QQuickItem *parent = 0); @@ -95,6 +96,11 @@ public: DnsErrorDomain }; + enum NewViewDestination { + NewViewInWindow, + NewViewInTab + }; + public Q_SLOTS: void loadHtml(const QString &html, const QUrl &baseUrl = QUrl(), const QUrl &unreachableUrl = QUrl()); void goBack(); @@ -118,6 +124,7 @@ private: Q_DECLARE_PRIVATE(QQuickWebEngineView) friend class QQuickWebEngineViewExperimental; friend class QQuickWebEngineViewExperimentalExtension; + friend class QQuickWebEngineNewViewRequest; }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index c7fecd477..4e0e8115d 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -55,6 +55,7 @@ class WebContentsAdapter; class UIDelegatesManager; QT_BEGIN_NAMESPACE +class QQuickWebEngineNewViewRequest; class QQuickWebEngineView; class QQmlComponent; class QQmlContext; @@ -77,18 +78,6 @@ 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) @@ -101,12 +90,11 @@ public: public Q_SLOTS: QQuickWebEngineViewport *viewport() const; - Q_INVOKABLE void adoptHandle(QQuickWebEngineViewHandle *viewHandle); void setExtraContextMenuEntriesComponent(QQmlComponent *); QQmlComponent *extraContextMenuEntriesComponent() const; Q_SIGNALS: - void createWindow(const QJSValue &newViewHandle, const QString &newViewDisposition); + void newViewRequested(QQuickWebEngineNewViewRequest *request); void fullScreenRequested(bool fullScreen); void isFullScreenChanged(); void extraContextMenuEntriesComponentChanged(); @@ -156,6 +144,7 @@ public: virtual void javaScriptConsoleMessage(int level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; void setDevicePixelRatio(qreal); + void adoptWebContents(WebContentsAdapter *webContents); QExplicitlySharedDataPointer<WebContentsAdapter> adapter; QScopedPointer<QQuickWebEngineViewExperimental> e; diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index dd36bc6b7..2408e5c8e 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -43,6 +43,7 @@ #include "qquickwebengineview_p.h" #include "qquickwebengineloadrequest_p.h" +#include "qquickwebenginenewviewrequest_p.h" QT_BEGIN_NAMESPACE @@ -57,6 +58,7 @@ public: qmlRegisterType<QQuickWebEngineView>(uri, 1, 0, "WebEngineView"); qmlRegisterUncreatableType<QQuickWebEngineLoadRequest>(uri, 1, 0, "WebEngineLoadRequest", QObject::tr("Cannot create separate instance of WebEngineLoadRequest")); + qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest>(uri, 1, 0, "WebEngineNewViewRequest", QObject::tr("Cannot create separate instance of WebEngineNewViewRequest")); } }; diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 877c515a9..dc95844a7 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -21,6 +21,7 @@ QMAKE_RPATHDIR += $$LIBPATH SOURCES = \ api/qquickwebengineloadrequest.cpp \ + api/qquickwebenginenewviewrequest.cpp \ api/qquickwebengineview.cpp \ render_widget_host_view_qt_delegate_quick.cpp \ ui_delegates_manager.cpp @@ -29,6 +30,7 @@ HEADERS = \ api/qtwebengineglobal.h \ api/qtwebengineglobal_p.h \ api/qquickwebengineloadrequest_p.h \ + api/qquickwebenginenewviewrequest_p.h \ api/qquickwebengineview_p.h \ api/qquickwebengineview_p_p.h \ render_widget_host_view_qt_delegate_quick.h \ |