From 853ad478e08157459ec995f5776019139df9f9bf Mon Sep 17 00:00:00 2001 From: Sheen Tian Shen Date: Mon, 28 Aug 2023 01:10:46 +0800 Subject: [PATCH] Fix popup --- example/QCefViewTest/CefViewWidget.cpp | 13 +- example/QCefViewTest/CefViewWidget.h | 13 +- example/QCefViewTest/MainWindow.cpp | 3 +- example/QCefViewTest/main.cpp | 3 +- include/QCefView.h | 46 +++--- src/QCefView.cpp | 48 +++--- src/details/CCefClientDelegate.h | 2 +- .../CCefClientDelegate_LifeSpanHandler.cpp | 72 +++++++-- src/details/QCefViewPrivate.cpp | 139 +++++++----------- src/details/QCefViewPrivate.h | 40 ++--- 10 files changed, 199 insertions(+), 180 deletions(-) diff --git a/example/QCefViewTest/CefViewWidget.cpp b/example/QCefViewTest/CefViewWidget.cpp index 87eed258..cd2786b1 100644 --- a/example/QCefViewTest/CefViewWidget.cpp +++ b/example/QCefViewTest/CefViewWidget.cpp @@ -54,12 +54,13 @@ CefViewWidget::onDraggableRegionChanged(const QRegion& draggableRegion, const QR } bool -CefViewWidget::onBeforePopup(qint64 frameId, - const QString& targetUrl, - const QString& targetFrameName, - QCefView::CefWindowOpenDisposition targetDisposition, - QRect& rect, - QCefSetting& settings) +CefViewWidget::onNewPopup(qint64 sourceFrameId, + const QString& targetUrl, + QString& targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings, + bool& disableJavascriptAccess) { // create new QCefView as popup browser settings.setBackgroundColor(Qt::red); diff --git a/example/QCefViewTest/CefViewWidget.h b/example/QCefViewTest/CefViewWidget.h index e4795c8e..c78a0396 100644 --- a/example/QCefViewTest/CefViewWidget.h +++ b/example/QCefViewTest/CefViewWidget.h @@ -30,12 +30,13 @@ protected slots: void onDraggableRegionChanged(const QRegion& draggableRegion, const QRegion& nonDraggableRegion); protected: - bool onBeforePopup(qint64 frameId, - const QString& targetUrl, - const QString& targetFrameName, - QCefView::CefWindowOpenDisposition targetDisposition, - QRect& rect, - QCefSetting& settings) override; + bool onNewPopup(qint64 sourceFrameId, + const QString& targetUrl, + QString& targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings, + bool& disableJavascriptAccess) override; void onNewDownloadItem(const QSharedPointer& item, const QString& suggestedName) override; diff --git a/example/QCefViewTest/MainWindow.cpp b/example/QCefViewTest/MainWindow.cpp index 99175149..7c00c679 100644 --- a/example/QCefViewTest/MainWindow.cpp +++ b/example/QCefViewTest/MainWindow.cpp @@ -102,7 +102,8 @@ MainWindow::createRightCefView() // this site is for test web events m_pRightCefViewWidget = new CefViewWidget("", &setting, this); - m_pRightCefViewWidget->navigateToUrl("https://fastest.fish/test-files"); + m_pRightCefViewWidget->navigateToUrl( + "https://www.javatpoint.com/oprweb/test.jsp?filename=javascript-window-close-method1"); // // m_pRightCefViewWidget = new CefViewWidget("https://mdn.dev/", &setting, this); diff --git a/example/QCefViewTest/main.cpp b/example/QCefViewTest/main.cpp index e56e1e5d..197e375f 100644 --- a/example/QCefViewTest/main.cpp +++ b/example/QCefViewTest/main.cpp @@ -26,7 +26,7 @@ main(int argc, char* argv[]) // WindowlessRenderingEnabled is set to true by default, // set to false to disable the OSR mode - config.setWindowlessRenderingEnabled(true); + config.setWindowlessRenderingEnabled(false); // add command line args, you can any cef supported switches or parameters config.addCommandLineSwitch("use-mock-keychain"); @@ -52,4 +52,3 @@ main(int argc, char* argv[]) // flying return a.exec(); } - diff --git a/include/QCefView.h b/include/QCefView.h index 9966cc6e..eb768bc0 100644 --- a/include/QCefView.h +++ b/include/QCefView.h @@ -107,12 +107,6 @@ class QCEFVIEW_EXPORT QCefView : public QWidget /// The browser id int browserId(); - /// - /// Gets whether the browser is created as popup browser - /// - /// True if it is popup browser; otherwise false - bool isPopup(); - /// /// Navigates to the content. /// @@ -408,20 +402,25 @@ class QCEFVIEW_EXPORT QCefView : public QWidget /// The native browser windows void nativeBrowserCreated(QWindow* window); +protected: /// - /// Gets called right after the popup browser was created. + /// /// - /// The new created popup QCefView instance - /// - /// The lifecycle of the popup browser is managed by the owner of the popup browser, - /// thus do not try to hold the popup browser instance. - /// If you need to implement browser tab, you should override the method - /// and create your own QCefView browser instance then you can manipulate the created one as whatever - /// you want. - /// - void popupCreated(QCefView* popup); + /// + /// + /// + /// + /// + /// + /// + /// + virtual QCefView* onNewBrowser(qint64 sourceFrameId, + const QString& url, + const QString& name, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings); -protected: /// /// Gets called before the popup browser created /// @@ -432,12 +431,13 @@ class QCEFVIEW_EXPORT QCefView : public QWidget /// Rect to be used for the popup /// Settings to be used for the popup /// True to cancel the popup; false to allow - virtual bool onBeforePopup(qint64 frameId, - const QString& targetUrl, - const QString& targetFrameName, - QCefView::CefWindowOpenDisposition targetDisposition, - QRect& rect, - QCefSetting& settings); + virtual bool onNewPopup(qint64 frameId, + const QString& targetUrl, + QString& targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings, + bool& disableJavascriptAccess); /// /// Gets called on new download item was required. Keep reference to the download item diff --git a/src/QCefView.cpp b/src/QCefView.cpp index 2f36b578..0a4df523 100644 --- a/src/QCefView.cpp +++ b/src/QCefView.cpp @@ -46,9 +46,6 @@ QCefView::~QCefView() qDebug() << this << "is being destructed"; if (d_ptr) { - // close all popup browsers - d_ptr->closeAllPopupBrowsers(); - // destroy under layer cef browser d_ptr->destroyCefBrowser(); d_ptr.reset(); @@ -82,14 +79,6 @@ QCefView::browserId() return d->browserId(); } -bool -QCefView::isPopup() -{ - Q_D(QCefView); - - return d->isPopup(); -} - void QCefView::navigateToString(const QString& content) { @@ -282,13 +271,38 @@ QCefView::setFocus(Qt::FocusReason reason) d->setCefWindowFocus(true); } +QCefView* +QCefView::onNewBrowser(qint64 sourceFrameId, + const QString& url, + const QString& name, + CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings) +{ + QCefView* popup = new QCefView(url, &settings, nullptr, Qt::WindowFlags()); + if (!popup) { + // failed to create QCefView, cancel popup + return nullptr; + } + + // config the popup QCefView + if (!name.isEmpty()) { + popup->setWindowTitle(name); + } + popup->resize(rect.size()); + popup->show(); + + return popup; +} + bool -QCefView::onBeforePopup(qint64 frameId, - const QString& targetUrl, - const QString& targetFrameName, - QCefView::CefWindowOpenDisposition targetDisposition, - QRect& rect, - QCefSetting& settings) +QCefView::onNewPopup(qint64 frameId, + const QString& targetUrl, + QString& targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings, + bool& disableJavascriptAccess) { return false; } diff --git a/src/details/CCefClientDelegate.h b/src/details/CCefClientDelegate.h index 0b600ce4..a03e0d6c 100644 --- a/src/details/CCefClientDelegate.h +++ b/src/details/CCefClientDelegate.h @@ -141,7 +141,7 @@ class CCefClientDelegate CefLifeSpanHandler::WindowOpenDisposition targetDisposition, CefWindowInfo& windowInfo, CefBrowserSettings& settings, - bool& DisableJavascriptAccess) override; + bool& disableJavascriptAccess) override; virtual void onAfterCreate(CefRefPtr& browser) override; virtual bool doClose(CefRefPtr browser) override; virtual void onBeforeClose(CefRefPtr browser) override; diff --git a/src/details/CCefClientDelegate_LifeSpanHandler.cpp b/src/details/CCefClientDelegate_LifeSpanHandler.cpp index 5c1402b3..cb8fae0d 100644 --- a/src/details/CCefClientDelegate_LifeSpanHandler.cpp +++ b/src/details/CCefClientDelegate_LifeSpanHandler.cpp @@ -5,6 +5,9 @@ #include "QCefSettingPrivate.h" #include "QCefViewPrivate.h" +#define DEFAULT_POPUP_WIDTH 800 +#define DEFAULT_POPUP_HEIGHT 600 + bool CCefClientDelegate::onBeforePopup(CefRefPtr& browser, int64_t frameId, @@ -13,24 +16,66 @@ CCefClientDelegate::onBeforePopup(CefRefPtr& browser, CefLifeSpanHandler::WindowOpenDisposition targetDisposition, CefWindowInfo& windowInfo, CefBrowserSettings& settings, - bool& DisableJavascriptAccess) + bool& disableJavascriptAccess) { - if (pCefViewPrivate_) { + bool cancel = true; + if (!pCefViewPrivate_) { + return cancel; + } + + auto url = QString::fromStdString(targetUrl); + auto name = QString::fromStdString(targetFrameName); + auto d = (QCefView::CefWindowOpenDisposition)targetDisposition; + auto rc = QRect(windowInfo.bounds.x, windowInfo.bounds.y, windowInfo.bounds.width, windowInfo.bounds.height); + + if (rc.width() <= 0) { + rc.setWidth(DEFAULT_POPUP_WIDTH); + } + + if (rc.height() <= 0) { + rc.setHeight(DEFAULT_POPUP_HEIGHT); + } + + QCefSetting s; + QCefSettingPrivate::CopyFromCefBrowserSettings(&s, &settings); - Qt::ConnectionType c = - pCefViewPrivate_->q_ptr->thread() == QThread::currentThread() ? Qt::DirectConnection : Qt::QueuedConnection; + if (targetDisposition == CefLifeSpanHandler::WindowOpenDisposition::WOD_NEW_POPUP) { + Qt::ConnectionType c = pCefViewPrivate_->q_ptr->thread() == QThread::currentThread() ? Qt::DirectConnection + : Qt::BlockingQueuedConnection; QMetaObject::invokeMethod( pCefViewPrivate_, - [=]() { - pCefViewPrivate_->onBeforeCefPopupCreate( - browser, frameId, targetUrl, targetFrameName, targetDisposition, windowInfo, settings); + [&]() { + cancel = pCefViewPrivate_->onBeforeNewPopupCreate(frameId, // + url, // + name, // + d, // + rc, // + s, // + disableJavascriptAccess); + if (!cancel) { + QCefSettingPrivate::CopyToCefBrowserSettings(&s, &settings); + CefString(&windowInfo.window_name) = name.toStdString(); + windowInfo.bounds = { rc.x(), rc.y(), rc.width(), rc.height() }; + } }, c); + } else { + cancel = true; + QMetaObject::invokeMethod( + pCefViewPrivate_, + [=]() { + pCefViewPrivate_->onBeforeNewBrowserCreate(frameId, // + url, // + name, // + d, // + rc, // + s); + }, + Qt::QueuedConnection); } - // QCefView doesn't use CEF built-in popup browser - return true; + return cancel; } void @@ -65,8 +110,13 @@ CCefClientDelegate::onAfterCreate(CefRefPtr& browser) } } - QMetaObject::invokeMethod( - pCefViewPrivate_, [=]() { pCefViewPrivate_->onCefBrowserCreated(browser, w); }, c); + if (browser->IsPopup()) { + QMetaObject::invokeMethod( + pCefViewPrivate_, [=]() { pCefViewPrivate_->onAfterCefPopupCreated(browser); }, c); + } else { + QMetaObject::invokeMethod( + pCefViewPrivate_, [=]() { pCefViewPrivate_->onCefBrowserCreated(browser, w); }, c); + } } bool diff --git a/src/details/QCefViewPrivate.cpp b/src/details/QCefViewPrivate.cpp index 89b066cb..8324fefd 100644 --- a/src/details/QCefViewPrivate.cpp +++ b/src/details/QCefViewPrivate.cpp @@ -7,9 +7,9 @@ #pragma region qt_headers #include #include +#include #include #include -#include #include #pragma endregion qt_headers @@ -30,9 +30,6 @@ #include "utils/MenuBuilder.h" #include "utils/ValueConvertor.h" -#define DEFAULT_POPUP_WIDTH 800 -#define DEFAULT_POPUP_HEIGHT 600 - QSet QCefViewPrivate::sLiveInstances; void @@ -83,10 +80,10 @@ QCefViewPrivate::createCefBrowser(QCefView* view, const QString url, const QCefS } // Set window info - CefWindowInfo window_info; + CefWindowInfo windowInfo; // #if defined(CEF_USE_OSR) if (isOSRModeEnabled_) { - window_info.SetAsWindowless(0); + windowInfo.SetAsWindowless(0); } else { // #else #if defined(Q_OS_LINUX) // Don't know why, on Linux platform if we use QCefView's winId() as @@ -94,15 +91,16 @@ QCefViewPrivate::createCefBrowser(QCefView* view, const QString url, const QCefS // and the browser window will not be created, this never happens // on Windows and macOS, so we create a temporal QWindow as the // parent to create CEF browser window. - QWindow w; - CefWindowHandle p = (CefWindowHandle)(w.winId()); - window_info.SetAsChild(p, { 0, 0, 0, 0 }); + QWindow* win = new QWindow(); + CefWindowHandle parent = (CefWindowHandle)win->winId(); #else + CefWindowHandle parent = (CefWindowHandle)view->winId(); +#endif + #if CEF_VERSION_MAJOR > 85 - window_info.SetAsChild((CefWindowHandle)view->winId(), { 0, 0, view->maximumWidth(), view->maximumHeight() }); + windowInfo.SetAsChild(parent, { 0, 0, 0, 0 }); #else - window_info.SetAsChild((CefWindowHandle)view->winId(), 0, 0, view->maximumWidth(), view->maximumHeight()); -#endif + windowInfo.SetAsChild(parent, 0, 0, 0, 0); #endif } // #endif @@ -119,7 +117,7 @@ QCefViewPrivate::createCefBrowser(QCefView* view, const QString url, const QCefS // #endif // create browser object - bool success = CefBrowserHost::CreateBrowser(window_info, // window info + bool success = CefBrowserHost::CreateBrowser(windowInfo, // window info pClient, // handler url.toStdString(), // url browserSettings, // settings @@ -158,14 +156,6 @@ QCefViewPrivate::destroyCefBrowser() pCefBrowser_ = nullptr; } -void -QCefViewPrivate::closeAllPopupBrowsers() -{ - for (auto popup : popupBrowsers_) { - popup->close(); - } -} - void QCefViewPrivate::addLocalFolderResource(const QString& path, const QString& url, int priority /*= 0*/) { @@ -253,9 +243,8 @@ QCefViewPrivate::onCefBrowserCreated(CefRefPtr browser, QWindow* win connect(qApp, &QApplication::focusChanged, this, &QCefViewPrivate::onAppFocusChanged); // initialize the layout and add browser widget to the layout - QVBoxLayout* layout = new QVBoxLayout(); + auto* layout = new QGridLayout(); layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); layout->addWidget(ncw.qBrowserWidget_); q_ptr->setLayout(layout); @@ -263,68 +252,52 @@ QCefViewPrivate::onCefBrowserCreated(CefRefPtr browser, QWindow* win UpdateCefWindowMask(ncw.qBrowserWindow_, q_ptr->mask()); } // #endif - - // if is popup browser record and show - if (isPopup_) { - // record - popupBrowsers_.insert(q_ptr); - - // show - q_ptr->show(); - - // emit the signal - q_ptr->popupCreated(q_ptr); - } } -void -QCefViewPrivate::onBeforeCefPopupCreate(const CefRefPtr& browser, - int64_t frameId, - const std::string& targetUrl, - const std::string& targetFrameName, - CefLifeSpanHandler::WindowOpenDisposition targetDisposition, - const CefWindowInfo& windowInfo, - const CefBrowserSettings& settings) +bool +QCefViewPrivate::onBeforeNewBrowserCreate(qint64 sourceFrameId, + QString targetUrl, + QString targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect rect, + QCefSetting settings) { Q_Q(QCefView); - auto url = QString::fromStdString(targetUrl); - auto name = QString::fromStdString(targetFrameName); - auto d = (QCefView::CefWindowOpenDisposition)targetDisposition; - auto rc = QRect(windowInfo.bounds.x, windowInfo.bounds.y, windowInfo.bounds.width, windowInfo.bounds.height); - - if (rc.width() <= 0) { - rc.setWidth(DEFAULT_POPUP_WIDTH); - } - - if (rc.height() <= 0) { - rc.setHeight(DEFAULT_POPUP_HEIGHT); - } - - QCefSetting s; - QCefSettingPrivate::CopyFromCefBrowserSettings(&s, &settings); - - if (q->onBeforePopup(frameId, url, name, d, rc, s)) { - // cancel popup - return; - } + // this is a fake popup browser, we just cancel it and then + // we create a new QCefView instance to replace the fake popup browser + q->onNewBrowser(sourceFrameId, // + targetUrl, // + targetFrameName, // + targetDisposition, // + rect, // + settings); + return true; +} - // allow popup, create QCefView as new popup browser - QCefView* popup = new QCefView(url, &s, nullptr, Qt::Window); - if (!popup) { - // failed to create QCefView, cancel popup - return; - } - popup->d_ptr->isPopup_ = true; +bool +QCefViewPrivate::onBeforeNewPopupCreate(qint64 sourceFrameId, + const QString& targetUrl, + QString& targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings, + bool& disableJavascriptAccess) +{ + Q_Q(QCefView); - connect(popup, SIGNAL(destroyed(QObject*)), this, SLOT(onPopupBrowserDestroyed(QObject*))); + return q->onNewPopup(sourceFrameId, // + targetUrl, // + targetFrameName, // + targetDisposition, // + rect, // + settings, // + disableJavascriptAccess); +} - // config the popup QCefView - if (!name.isEmpty()) { - popup->setWindowTitle(name); - } - popup->setAttribute(Qt::WA_DeleteOnClose, true); - popup->resize(rc.size()); +void +QCefViewPrivate::onAfterCefPopupCreated(CefRefPtr browser) +{ } void @@ -363,12 +336,6 @@ QCefViewPrivate::handleLoadError(CefRefPtr& browser, return false; } -void -QCefViewPrivate::onPopupBrowserDestroyed(QObject* popup) -{ - popupBrowsers_.remove(static_cast(popup)); -} - void QCefViewPrivate::onAppFocusChanged(QWidget* old, QWidget* now) { @@ -980,12 +947,6 @@ QCefViewPrivate::browserId() return -1; } -bool -QCefViewPrivate::isPopup() -{ - return isPopup_; -} - void QCefViewPrivate::navigateToString(const QString& content) { diff --git a/src/details/QCefViewPrivate.h b/src/details/QCefViewPrivate.h index 0c32eefe..8d7b0241 100644 --- a/src/details/QCefViewPrivate.h +++ b/src/details/QCefViewPrivate.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -38,11 +37,6 @@ class QCefViewPrivate : public QObject /// static void destroyAllInstance(); - /// - /// - /// - bool isPopup_ = false; - /// /// /// @@ -170,11 +164,6 @@ class QCefViewPrivate : public QObject QElapsedTimer paintTimer_; #endif - /// - /// The list of popup child-browsers of this browser. - /// - QSet popupBrowsers_; - public: explicit QCefViewPrivate(QCefContextPrivate* ctx, QCefView* view, @@ -187,8 +176,6 @@ class QCefViewPrivate : public QObject void destroyCefBrowser(); - void closeAllPopupBrowsers(); - void addLocalFolderResource(const QString& path, const QString& url, int priority = 0); void addArchiveResource(const QString& path, const QString& url, const QString& password = "", int priority = 0); @@ -200,13 +187,22 @@ class QCefViewPrivate : public QObject protected: void onCefBrowserCreated(CefRefPtr browser, QWindow* window); - void onBeforeCefPopupCreate(const CefRefPtr& browser, - int64_t frameId, - const std::string& targetUrl, - const std::string& targetFrameName, - CefLifeSpanHandler::WindowOpenDisposition targetDisposition, - const CefWindowInfo& windowInfo, - const CefBrowserSettings& settings); + bool onBeforeNewBrowserCreate(qint64 sourceFrameId, + QString targetUrl, + QString targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect rect, + QCefSetting settings); + + bool onBeforeNewPopupCreate(qint64 sourceFrameId, + const QString& targetUrl, + QString& targetFrameName, + QCefView::CefWindowOpenDisposition targetDisposition, + QRect& rect, + QCefSetting& settings, + bool& disableJavascriptAccess); + + void onAfterCefPopupCreated(CefRefPtr browser); void onNewDownloadItem(QSharedPointer item, const QString& suggestedName); @@ -219,8 +215,6 @@ class QCefViewPrivate : public QObject const std::string& failedUrl); public slots: - void onPopupBrowserDestroyed(QObject* popup); - void onAppFocusChanged(QWidget* old, QWidget* now); void onViewScreenChanged(QScreen* screen); @@ -287,8 +281,6 @@ public slots: public: int browserId(); - bool isPopup(); - void navigateToString(const QString& content); void navigateToUrl(const QString& url);