diff --git a/lib/quick/qquickwebengineview_p_p.h b/lib/quick/qquickwebengineview_p_p.h index 947886c441f2450e1e6631d5c4dc713605d3adf0..54bc21628d9c6a1d7378a131429677ff433ad78f 100644 --- a/lib/quick/qquickwebengineview_p_p.h +++ b/lib/quick/qquickwebengineview_p_p.h @@ -68,6 +68,7 @@ public: virtual void loadFinished(bool success) Q_DECL_OVERRIDE; virtual void focusContainer() Q_DECL_OVERRIDE; virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition) Q_DECL_OVERRIDE; + virtual bool contextMenuRequested(const WebEngineContextMenuData &) Q_DECL_OVERRIDE { return false;} QExplicitlySharedDataPointer<WebContentsAdapter> adapter; QUrl icon; diff --git a/lib/web_contents_adapter_client.h b/lib/web_contents_adapter_client.h index 39968a8a503d9ffce9c5c85e8969395efa5b3f35..8e92ead7c1f97968777edf0a354596cd06daca20 100644 --- a/lib/web_contents_adapter_client.h +++ b/lib/web_contents_adapter_client.h @@ -47,12 +47,28 @@ #include <QString> #include <QUrl> - class RenderWidgetHostViewQt; class RenderWidgetHostViewQtDelegate; class WebContentsAdapter; class WebContentsDelegateQt; +// FIXME: make this ref-counted and implicitely shared and expose as public API maybe ? +class WebEngineContextMenuData { + +public: + QPoint pos; + QUrl linkUrl; + QString linkText; + QString selectedText; +// Some likely candidates for future additions as we add support for the related actions: +// bool isImageBlocked; +// bool isEditable; +// bool isSpellCheckingEnabled; +// QStringList spellCheckingSuggestions; +// <enum tbd> mediaType; +// ... +}; + class QWEBENGINE_EXPORT WebContentsAdapterClient { public: enum CompositingMode { @@ -87,6 +103,7 @@ public: virtual void loadFinished(bool success) = 0; virtual void focusContainer() = 0; virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition) = 0; + virtual bool contextMenuRequested(const WebEngineContextMenuData&) = 0; }; #endif // WEB_CONTENTS_ADAPTER_CLIENT_H diff --git a/lib/web_contents_view_qt.cpp b/lib/web_contents_view_qt.cpp index 340075c9a6d1c935f549feffd2538dba5ce80700..8fc7f5b12bed9c92e6fb41f742cc243e3db01ff3 100644 --- a/lib/web_contents_view_qt.cpp +++ b/lib/web_contents_view_qt.cpp @@ -48,6 +48,7 @@ #include "base/command_line.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/public/common/content_switches.h" +#include "content/public/common/context_menu_params.h" void WebContentsViewQt::initialize(WebContentsAdapterClient* client) { @@ -111,3 +112,19 @@ void WebContentsViewQt::SetInitialFocus() { Focus(); } + +static WebEngineContextMenuData fromParams(const content::ContextMenuParams ¶ms) +{ + WebEngineContextMenuData ret; + ret.pos = QPoint(params.x, params.y); + ret.linkUrl = toQt(params.link_url); + ret.linkText = toQt(params.link_text.data()); + ret.selectedText = toQt(params.selection_text.data()); + return ret; +} + +void WebContentsViewQt::ShowContextMenu(const content::ContextMenuParams ¶ms) +{ + WebEngineContextMenuData contextMenuData(fromParams(params)); + m_client->contextMenuRequested(contextMenuData); +} diff --git a/lib/web_contents_view_qt.h b/lib/web_contents_view_qt.h index b76c725455ed54b70812568235304a459fbd378f..d71369762246cc8ae257605df2d539111648f3ce 100644 --- a/lib/web_contents_view_qt.h +++ b/lib/web_contents_view_qt.h @@ -107,6 +107,8 @@ public: virtual void ShowPopupMenu(const gfx::Rect& bounds, int item_height, double item_font_size, int selected_item, const std::vector<content::MenuItem>& items, bool right_aligned, bool allow_multiple_selection) { QT_NOT_YET_IMPLEMENTED } + virtual void ShowContextMenu(const content::ContextMenuParams ¶ms); + #if defined(OS_MACOSX) virtual void SetAllowOverlappingViews(bool overlapping) { QT_NOT_YET_IMPLEMENTED } virtual void CloseTabAfterEventTracking() { QT_NOT_YET_IMPLEMENTED } diff --git a/lib/widgets/Api/qwebenginepage.cpp b/lib/widgets/Api/qwebenginepage.cpp index 8fafb3c47434d7d52d8955bdafca9f587ae1bb75..b956a878584e62430538604e4746eae6f58f6b9e 100644 --- a/lib/widgets/Api/qwebenginepage.cpp +++ b/lib/widgets/Api/qwebenginepage.cpp @@ -31,7 +31,11 @@ #include "web_contents_adapter.h" #include <QAction> +#include <QApplication> +#include <QClipboard> +#include <QIcon> #include <QLayout> +#include <QMenu> #include <QUrl> QT_BEGIN_NAMESPACE @@ -269,6 +273,78 @@ void QWebEnginePage::triggerAction(WebAction action, bool) } } +bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData &data) +{ + if (!view) + return false; + + QContextMenuEvent event(QContextMenuEvent::Mouse, data.pos, view->mapToGlobal(data.pos)); + switch (view->contextMenuPolicy()) { + case Qt::PreventContextMenu: + return false; + case Qt::DefaultContextMenu: + m_menuData = data; + view->contextMenuEvent(&event); + break; + case Qt::CustomContextMenu: + Q_EMIT view->customContextMenuRequested(data.pos); + break; + case Qt::ActionsContextMenu: + if (view->actions().count()) { + QMenu::exec(view->actions(), event.globalPos(), 0, view); + break; + } + // fall through + default: + event.ignore(); + return false; + break; + } + Q_ASSERT(view->d_func()->m_pendingContextMenuEvent); + view->d_func()->m_pendingContextMenuEvent = false; + m_menuData = WebEngineContextMenuData(); + return true; +} + +QMenu *QWebEnginePage::createStandardContextMenu() +{ + Q_D(QWebEnginePage); + QMenu *menu = new QMenu(d->view); + QAction *action = 0; + WebEngineContextMenuData contextMenuData(d->m_menuData); + if (contextMenuData.selectedText.isEmpty()) { + action = new QAction(QIcon::fromTheme(QStringLiteral("go-previous")), tr("&Back"), menu); + connect(action, &QAction::triggered, d->view, &QWebEngineView::back); + action->setEnabled(d->adapter->canGoBack()); + menu->addAction(action); + + action = new QAction(QIcon::fromTheme(QStringLiteral("go-next")), tr("&Forward"), menu); + connect(action, &QAction::triggered, d->view, &QWebEngineView::forward); + action->setEnabled(d->adapter->canGoForward()); + menu->addAction(action); + + action = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), tr("&Reload"), menu); + connect(action, &QAction::triggered, d->view, &QWebEngineView::reload); + menu->addAction(action); + } else { + action = new QAction(tr("Copy..."), menu); + // FIXME: We probably can't keep "cheating" with lambdas, but for now it keeps this patch smaller ;) + connect(action, &QAction::triggered, [=]() { qApp->clipboard()->setText(contextMenuData.selectedText); }); + menu->addAction(action); + } + + if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) { + menu->addSeparator(); + action = new QAction(tr("Navigate to..."), menu); + connect(action, &QAction::triggered, [=]() { load(contextMenuData.linkUrl); }); + menu->addAction(action); + action = new QAction(tr("Copy link address"), menu); + connect(action, &QAction::triggered, [=]() { qApp->clipboard()->setText(contextMenuData.linkUrl.toString()); }); + menu->addAction(action); + } + return menu; +} + void QWebEnginePage::load(const QUrl& url) { Q_D(QWebEnginePage); diff --git a/lib/widgets/Api/qwebenginepage_p.h b/lib/widgets/Api/qwebenginepage_p.h index e8f511d2d6668c7fe6b14ad68462aeba155c94ca..56080c97726d728903e80c5dcf723a63d2a3156b 100644 --- a/lib/widgets/Api/qwebenginepage_p.h +++ b/lib/widgets/Api/qwebenginepage_p.h @@ -74,6 +74,7 @@ public: virtual void loadFinished(bool success) Q_DECL_OVERRIDE; virtual void focusContainer() Q_DECL_OVERRIDE; virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition) Q_DECL_OVERRIDE; + virtual bool contextMenuRequested(const WebEngineContextMenuData &data) Q_DECL_OVERRIDE; void updateAction(QWebEnginePage::WebAction) const; void updateNavigationActions(); @@ -84,6 +85,7 @@ public: QWebEngineView *view; mutable QAction *actions[QWebEnginePage::WebActionCount]; bool m_isLoading; + WebEngineContextMenuData m_menuData; }; QT_END_NAMESPACE diff --git a/lib/widgets/Api/qwebengineview.cpp b/lib/widgets/Api/qwebengineview.cpp index d07e710abe2bd2c7790a42e0463c40986bc0de4e..536f075f3954cce2286153a8bd838b36f4f02a63 100644 --- a/lib/widgets/Api/qwebengineview.cpp +++ b/lib/widgets/Api/qwebengineview.cpp @@ -44,6 +44,9 @@ #include "qwebenginepage_p.h" +#include <QAction> +#include <QMenu> +#include <QContextMenuEvent> #include <QStackedLayout> QT_BEGIN_NAMESPACE @@ -186,6 +189,24 @@ void QWebEngineView::setZoomFactor(qreal factor) page()->setZoomFactor(factor); } +bool QWebEngineView::event(QEvent *ev) +{ + Q_D(QWebEngineView); + // We swallow spontaneous contextMenu events and synthethize those back later on when we get the + // HandleContextMenu callback from chromium + if (ev->type() == QEvent::ContextMenu) { + ev->accept(); + return true; + } + return QWidget::event(ev); +} + +void QWebEngineView::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu *menu = page()->createStandardContextMenu(); + menu->popup(event->globalPos()); +} + QT_END_NAMESPACE #include "moc_qwebengineview.cpp" diff --git a/lib/widgets/Api/qwebengineview.h b/lib/widgets/Api/qwebengineview.h index c3b3067bce3c5f6645342357d1ea92699faad784..2c649d46f24d0e72c013b5bbfbbe07a5e4bf745e 100644 --- a/lib/widgets/Api/qwebengineview.h +++ b/lib/widgets/Api/qwebengineview.h @@ -30,6 +30,7 @@ #include <QtWebEngineWidgets/qwebenginepage.h> QT_BEGIN_NAMESPACE +class QContextMenuEvent; class QIcon; class QNetworkRequest; class QPrinter; @@ -129,11 +130,14 @@ Q_SIGNALS: protected: virtual QWebEngineView *createWindow(QWebEnginePage::WebWindowType type); + virtual void contextMenuEvent(QContextMenuEvent*) Q_DECL_OVERRIDE; + virtual bool event(QEvent*) Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(QWebEngineView); friend class QWebEnginePage; + friend class QWebEnginePagePrivate; }; QT_END_NAMESPACE diff --git a/lib/widgets/Api/qwebengineview_p.h b/lib/widgets/Api/qwebengineview_p.h index 73e5d45d8f0bb2acc6a37679ace05be0d8f7731e..774386a213cea85ae79fd4cb1e6d2889e74d3862 100644 --- a/lib/widgets/Api/qwebengineview_p.h +++ b/lib/widgets/Api/qwebengineview_p.h @@ -59,6 +59,7 @@ public: QWebEngineViewPrivate(); QWebEnginePage *page; + bool m_pendingContextMenuEvent; }; QT_END_NAMESPACE diff --git a/lib/widgets/widgets.pro b/lib/widgets/widgets.pro index 272e3568edd6841d9735874c62e296f9553e5a40..60730f880ababd057685d2d70bea5d5842c768ea 100644 --- a/lib/widgets/widgets.pro +++ b/lib/widgets/widgets.pro @@ -9,6 +9,8 @@ MODULE = webenginewidgets # For our export macros DEFINES += QT_BUILD_WEBENGINEWIDGETS_LIB +CONFIG += c++11 + QT += widgets QT_PRIVATE += widgets-private gui-private core-private