diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 865fd55d780725836c51c51780217036bdff36bd..85a3794099f95172598a4880f20d798d3550367c 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -71,23 +71,43 @@ class WebContentsAdapter;
 class WebContentsDelegateQt;
 class WebEngineSettings;
 
-// FIXME: make this ref-counted and implicitely shared and expose as public API maybe ?
-class WebEngineContextMenuData {
+
+class WebEngineContextMenuSharedData : public QSharedData {
 
 public:
-    WebEngineContextMenuData()
-        : mediaType(MediaTypeNone)
-        , hasImageContent(false)
-        , mediaFlags(0)
+    WebEngineContextMenuSharedData()
+        :  hasImageContent(false)
         , isEditable(false)
         , isSpellCheckerEnabled(false)
+        , mediaType(0)
+        , mediaFlags(0)
     {
     }
+    bool hasImageContent;
+    bool isEditable;
+    bool isSpellCheckerEnabled;
+    uint mediaType;
+    uint mediaFlags;
+    QPoint pos;
+    QUrl linkUrl;
+    QUrl mediaUrl;
+    QString linkText;
+    QString selectedText;
+    QString suggestedFileName;
+    QString misspelledWord;
+    QStringList spellCheckerSuggestions;
+    // Some likely candidates for future additions as we add support for the related actions:
+    //    bool isImageBlocked;
+    //    <enum tbd> mediaType;
+    //    ...
+};
 
+class WebEngineContextMenuData {
+public:
     // Must match blink::WebContextMenuData::MediaType:
     enum MediaType {
         // No special node is in context.
-        MediaTypeNone,
+        MediaTypeNone = 0x0,
         // An image node is selected.
         MediaTypeImage,
         // A video node is selected.
@@ -117,25 +137,118 @@ public:
         MediaCanRotate = 0x200,
     };
 
-    QPoint pos;
-    QUrl linkUrl;
-    QString linkText;
-    QString selectedText;
-    QUrl mediaUrl;
-    MediaType mediaType;
-    bool hasImageContent;
-    uint mediaFlags;
-    QString suggestedFileName;
-    bool isEditable;
-    bool isSpellCheckerEnabled;
-    QString misspelledWord;
-    QStringList spellCheckerSuggestions;
-// Some likely candidates for future additions as we add support for the related actions:
-//    bool isImageBlocked;
-//    <enum tbd> mediaType;
-//    ...
+    WebEngineContextMenuData():d(new WebEngineContextMenuSharedData) {
+    }
+
+    void setPosition(const QPoint &pos) {
+        d->pos = pos;
+    }
+
+    QPoint position() const {
+        return d->pos;
+    }
+
+    void setLinkUrl(const QUrl &url) {
+        d->linkUrl = url;
+    }
+
+    QUrl linkUrl() const {
+        return d->linkUrl;
+    }
+
+    void setLinkText(const QString &text) {
+        d->linkText = text;
+    }
+
+    QString linkText() const {
+        return d->linkText;
+    }
+
+    void setSelectedText(const QString &text) {
+        d->selectedText = text;
+    }
+
+    QString selectedText() const {
+        return d->selectedText;
+    }
+
+    void setMediaUrl(const QUrl &url) {
+        d->mediaUrl = url;
+    }
+
+    QUrl mediaUrl() const {
+        return d->mediaUrl;
+    }
+
+    void setMediaType(MediaType type) {
+        d->mediaType = type;
+    }
+
+    MediaType mediaType() const {
+        return MediaType(d->mediaType);
+    }
+
+    void setHasImageContent(bool imageContent) {
+        d->hasImageContent = imageContent;
+    }
+
+    bool hasImageContent() const {
+        return d->hasImageContent;
+    }
+
+    void setMediaFlags(MediaFlags flags) {
+        d->mediaFlags = flags;
+    }
+
+    MediaFlags mediaFlags() const {
+        return MediaFlags(d->mediaFlags);
+    }
+
+    void setSuggestedFileName(const QString &filename) {
+        d->suggestedFileName = filename;
+    }
+
+    QString suggestedFileName() const {
+        return d->suggestedFileName;
+    }
+
+    void setIsEditable(bool editable) {
+        d->isEditable = editable;
+    }
+
+    bool isEditable() const {
+        return d->isEditable;
+    }
+
+    void setIsSpellCheckerEnabled(bool spellCheckerEnabled) {
+        d->isSpellCheckerEnabled = spellCheckerEnabled;
+    }
+
+    bool isSpellCheckerEnabled() const {
+        return d->isSpellCheckerEnabled;
+    }
+
+    void setMisspelledWord(const QString &word) {
+        d->misspelledWord = word;
+    }
+
+    QString misspelledWord() const {
+        return d->misspelledWord;
+    }
+
+    void setSpellCheckerSuggestions(const QStringList &suggestions) {
+        d->spellCheckerSuggestions = suggestions;
+    }
+
+    QStringList spellCheckerSuggestions() const {
+        return d->spellCheckerSuggestions;
+    }
+
+private:
+    QSharedDataPointer<WebEngineContextMenuSharedData> d;
 };
 
+
 class QWEBENGINE_EXPORT WebContentsAdapterClient {
 public:
     // This must match window_open_disposition_list.h.
diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp
index e487fca46f450dbd25c5055135bb4efe53655f1a..ed6fdabff5ec95ee26a41dd993ed10db1806698c 100644
--- a/src/core/web_contents_view_qt.cpp
+++ b/src/core/web_contents_view_qt.cpp
@@ -155,19 +155,19 @@ ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanRotate, blink::WebContextMe
 static inline WebEngineContextMenuData fromParams(const content::ContextMenuParams &params)
 {
     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());
-    ret.mediaUrl = toQt(params.src_url);
-    ret.mediaType = (WebEngineContextMenuData::MediaType)params.media_type;
-    ret.hasImageContent = params.has_image_contents;
-    ret.mediaFlags = params.media_flags;
-    ret.suggestedFileName = toQt(params.suggested_filename.data());
-    ret.isEditable = params.is_editable;
+    ret.setPosition(QPoint(params.x, params.y));
+    ret.setLinkUrl(toQt(params.link_url));
+    ret.setLinkText(toQt(params.link_text.data()));
+    ret.setSelectedText(toQt(params.selection_text.data()));
+    ret.setMediaUrl(toQt(params.src_url));
+    ret.setMediaType((WebEngineContextMenuData::MediaType)params.media_type);
+    ret.setHasImageContent(params.has_image_contents);
+    ret.setMediaFlags((WebEngineContextMenuData::MediaFlags)params.media_flags);
+    ret.setSuggestedFileName(toQt(params.suggested_filename.data()));
+    ret.setIsEditable(params.is_editable);
 #if defined(ENABLE_SPELLCHECK)
-    ret.misspelledWord = toQt(params.misspelled_word);
-    ret.spellCheckerSuggestions = fromVector(params.dictionary_suggestions);
+    ret.setMisspelledWord(toQt(params.misspelled_word));
+    ret.setSpellCheckerSuggestions(fromVector(params.dictionary_suggestions));
 #endif
     return ret;
 }
@@ -183,7 +183,7 @@ void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, const conten
     // must be initialized to true due to the way how the initialization sequence
     // in SpellCheck works ie. typing the first word triggers the creation
     // of the SpellcheckService. Use user preference store instead.
-    contextMenuData.isSpellCheckerEnabled = m_client->browserContextAdapter()->isSpellCheckEnabled();
+    contextMenuData.setIsSpellCheckerEnabled(m_client->browserContextAdapter()->isSpellCheckEnabled());
 #endif
     m_client->contextMenuRequested(contextMenuData);
 }
diff --git a/src/webengine/api/qquickwebenginecontextmenudata.cpp b/src/webengine/api/qquickwebenginecontextmenudata.cpp
deleted file mode 100644
index 36315aebba850c8e0443b91924d8f01700de1dc4..0000000000000000000000000000000000000000
--- a/src/webengine/api/qquickwebenginecontextmenudata.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** 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 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$
-**
-****************************************************************************/
-
-#include "qquickwebenginecontextmenudata_p.h"
-
-#include "web_contents_adapter_client.h"
-
-QT_BEGIN_NAMESPACE
-
-ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeNone,   QQuickWebEngineContextMenuData::MediaTypeNone)
-ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeImage,  QQuickWebEngineContextMenuData::MediaTypeImage)
-ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeAudio,  QQuickWebEngineContextMenuData::MediaTypeAudio)
-ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeVideo,  QQuickWebEngineContextMenuData::MediaTypeVideo)
-ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeCanvas, QQuickWebEngineContextMenuData::MediaTypeCanvas)
-ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeFile,   QQuickWebEngineContextMenuData::MediaTypeFile)
-ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypePlugin, QQuickWebEngineContextMenuData::MediaTypePlugin)
-
-/*!
-    \qmltype WebEngineContextMenuData
-    \instantiates QQuickWebEngineContextMenuData
-    \inqmlmodule QtWebEngine
-    \since QtWebEngine 1.3
-    \brief Provides context data for populating or extending a context menu with actions.
-
-
-    WebEngineContextMenuData is returned by WebEngineView::contextMenuData() after a context menu event,
-    and contains information about where the context menu event took place. This is also in the context
-    in which any context specific WebEngineView::WebAction will be performed.
-*/
-
-QQuickWebEngineContextMenuData::QQuickWebEngineContextMenuData() : d(nullptr)
-{
-}
-
-QQuickWebEngineContextMenuData::~QQuickWebEngineContextMenuData()
-{
-    delete d;
-}
-
-/*!
-    \qmlproperty bool WebEngineContextMenuData::isValid
-
-    Is \c true if the context data is valid; otherwise \c false.
-*/
-bool QQuickWebEngineContextMenuData::isValid() const
-{
-    return d;
-}
-
-/*!
-    \qmlproperty QPoint WebEngineContextMenuData::position
-
-
-    Returns the position of the context, usually the mouse position where the context menu event was triggered.
-*/
-QPoint QQuickWebEngineContextMenuData::position() const
-{
-    return d ? d->pos : QPoint();
-}
-
-/*!
-    \qmlproperty QString WebEngineContextMenuData::linkText
-
-    Returns the text of a link if the context is a link.
-*/
-QString QQuickWebEngineContextMenuData::linkText() const
-{
-    return d ? d->linkText : QString();
-}
-
-/*!
-    \qmlproperty QUrl WebEngineContextMenuData::linkUrl
-
-    Returns the URL of a link if the context is a link.
-*/
-QUrl QQuickWebEngineContextMenuData::linkUrl() const
-{
-    return d ? d->linkUrl : QUrl();
-}
-
-/*!
-    \qmlproperty QString WebEngineContextMenuData::selectedText
-
-    Returns the selected text of the context.
-*/
-QString QQuickWebEngineContextMenuData::selectedText() const
-{
-    return d ? d->selectedText : QString();
-}
-
-/*!
-    \qmlproperty QUrl WebEngineContextMenuData::mediaUrl
-
-    If the context is a media element, returns the URL of that media.
-*/
-QUrl QQuickWebEngineContextMenuData::mediaUrl() const
-{
-    return d ? d->mediaUrl : QUrl();
-}
-
-/*!
-    \qmlproperty enumeration WebEngineContextMenuData::mediaType
-
-    Returns the type of the media element or \c MediaTypeNone if the context is not a media element.
-
-    \value  WebEngineContextMenuData.MediaTypeNone
-            The context is not a media element.
-    \value  WebEngineContextMenuData.MediaTypeImage
-            The context is an image element
-    \value  WebEngineContextMenuData.MediaTypeVideo
-            The context is a video element
-    \value  WebEngineContextMenuData.MediaTypeAudio
-            The context is an audio element
-    \value  WebEngineContextMenuData.MediaTypeCanvas
-            The context is a canvas element
-    \value  WebEngineContextMenuData.MediaTypeFile
-            The context is a file
-    \value  WebEngineContextMenuData.MediaTypePlugin
-            The context is a plugin
-*/
-
-QQuickWebEngineContextMenuData::MediaType QQuickWebEngineContextMenuData::mediaType() const
-{
-    return d ? static_cast<QQuickWebEngineContextMenuData::MediaType>(d->mediaType) : MediaTypeNone;
-}
-
-/*!
-    \qmlproperty bool WebEngineContextMenuData::isContentEditable
-
-    Returns \c true if the content is editable by the user; otherwise returns \c false.
-*/
-bool QQuickWebEngineContextMenuData::isContentEditable() const
-{
-    return d ? d->isEditable : false;
-}
-
-/*!
-    \qmlproperty QString WebEngineContextMenuData::misspelledWord
-
-    If the context is a word considered misspelled by the spell-checker, returns the misspelled word.
-
-    \since QtWebEngine 1.4
-*/
-QString QQuickWebEngineContextMenuData::misspelledWord() const
-{
-    if (d)
-        return d->misspelledWord;
-    return QString();
-}
-
-/*!
-    \qmlproperty QStringList WebEngineContextMenuData::spellCheckerSuggestions
-
-    If the context is a word considered misspelled by the spell-checker, returns a list of suggested replacements.
-
-    \since QtWebEngine 1.4
-*/
-QStringList QQuickWebEngineContextMenuData::spellCheckerSuggestions() const
-{
-    if (d)
-        return d->spellCheckerSuggestions;
-    return QStringList();
-}
-
-void QQuickWebEngineContextMenuData::update(const QtWebEngineCore::WebEngineContextMenuData &update)
-{
-    const QQuickWebEngineContextMenuData old(d);
-    d = new QtWebEngineCore::WebEngineContextMenuData(update);
-
-    if (isValid() != old.isValid())
-        Q_EMIT isValidChanged();
-
-    if (position() != old.position())
-        Q_EMIT positionChanged();
-
-    if (selectedText() != old.selectedText())
-        Q_EMIT selectedTextChanged();
-
-    if (linkText() != old.linkText())
-        Q_EMIT linkTextChanged();
-
-    if (linkUrl() != old.linkUrl())
-        Q_EMIT linkUrlChanged();
-
-    if (mediaUrl() != old.mediaUrl())
-        Q_EMIT mediaUrlChanged();
-
-    if (mediaType() != old.mediaType())
-        Q_EMIT mediaTypeChanged();
-
-    if (isContentEditable() != old.isContentEditable())
-        Q_EMIT isContentEditableChanged();
-
-    if (misspelledWord() != old.misspelledWord())
-        Q_EMIT misspelledWordChanged();
-
-    if (spellCheckerSuggestions() != old.spellCheckerSuggestions())
-        Q_EMIT spellCheckerSuggestionsChanged();
-}
-
-QQuickWebEngineContextMenuData::QQuickWebEngineContextMenuData(const QQuickWebEngineContextMenuDataPrivate *p, QObject *parent)
-    : QObject(parent)
-    , d(p)
-{
-}
-
-QT_END_NAMESPACE
diff --git a/src/webengine/api/qquickwebenginecontextmenurequest.cpp b/src/webengine/api/qquickwebenginecontextmenurequest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ad2b1501fa66bd3a2d3a8de08511ce784253694
--- /dev/null
+++ b/src/webengine/api/qquickwebenginecontextmenurequest.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 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$
+**
+****************************************************************************/
+
+#include "qquickwebenginecontextmenurequest_p.h"
+#include "web_contents_adapter_client.h"
+
+QT_BEGIN_NAMESPACE
+
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeNone,
+                   QQuickWebEngineContextMenuRequest::MediaTypeNone)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeImage,
+                   QQuickWebEngineContextMenuRequest::MediaTypeImage)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeAudio,
+                   QQuickWebEngineContextMenuRequest::MediaTypeAudio)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeVideo,
+                   QQuickWebEngineContextMenuRequest::MediaTypeVideo)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeCanvas,
+                   QQuickWebEngineContextMenuRequest::MediaTypeCanvas)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeFile,
+                   QQuickWebEngineContextMenuRequest::MediaTypeFile)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypePlugin,
+                   QQuickWebEngineContextMenuRequest::MediaTypePlugin)
+
+/*!
+    \qmltype ContextMenuRequest
+    \instantiates QQuickWebEngineContextMenuRequest
+    \inqmlmodule QtWebEngine
+    \since QtWebEngine 1.4
+
+    \brief A request for showing a context menu.
+
+    A ContextMenuRequest is passed as an argument of the
+    WebEngineView::contextMenuRequested signal. It provides further
+    information about the context of the request. The position of the
+    request origin can be found via the \l x and \l y properties.
+
+    The \l accepted property of the request indicates whether the request
+    is handled by the user code or the default context menu should
+    be displayed.
+
+    The following code uses a custom menu to handle the request:
+
+    \code
+    WebEngineView {
+        id: view
+        // ...
+        onContextMenuRequested: {
+            request.accepted = true;
+            myMenu.x = request.x;
+            myMenu.y = request.y;
+            myMenu.trigger.connect(view.triggerWebAction);
+            myMenu.popup();
+        }
+        // ...
+    }
+    \endcode
+*/
+
+QQuickWebEngineContextMenuRequest::QQuickWebEngineContextMenuRequest(
+        const QtWebEngineCore::WebEngineContextMenuData &data, QObject *parent):
+    QObject(parent)
+  , m_data(new QtWebEngineCore::WebEngineContextMenuData(data))
+  , m_accepted(false)
+{
+}
+
+QQuickWebEngineContextMenuRequest::~QQuickWebEngineContextMenuRequest()
+{
+}
+
+/*!
+    \qmlproperty int ContextMenuRequest::x
+    \readonly
+
+    The x coordinate of the user action from where the context
+    menu request originates.
+*/
+
+int QQuickWebEngineContextMenuRequest::x() const
+{
+    return m_data->position().x();
+}
+
+/*!
+    \qmlproperty int ContextMenuRequest::y
+    \readonly
+
+    The y coordinate of the user action from where the context
+    menu request originates.
+*/
+
+int QQuickWebEngineContextMenuRequest::y() const
+{
+    return m_data->position().y();
+}
+
+/*!
+    \qmlproperty string ContextMenuRequest::selectedText
+    \readonly
+
+    The selected text the context menu was created for.
+*/
+
+QString QQuickWebEngineContextMenuRequest::selectedText() const
+{
+    return m_data->selectedText();
+}
+
+/*!
+    \qmlproperty string ContextMenuRequest::linkText
+    \readonly
+
+    The text of the link if the context menu was requested for a link.
+*/
+
+QString QQuickWebEngineContextMenuRequest::linkText() const
+{
+    return m_data->linkText();
+}
+
+/*!
+    \qmlproperty url ContextMenuRequest::linkUrl
+    \readonly
+
+    The URL of the link if the selected web page content is a link.
+*/
+
+QUrl QQuickWebEngineContextMenuRequest::linkUrl() const
+{
+    return m_data->linkUrl();
+}
+
+/*!
+    \qmlproperty url ContextMenuRequest::mediaUrl
+    \readonly
+
+    The URL of media if the selected web content is a media element.
+*/
+
+QUrl QQuickWebEngineContextMenuRequest::mediaUrl() const
+{
+    return m_data->mediaUrl();
+}
+
+/*!
+    \qmlproperty enumeration ContextMenuRequest::mediaType
+    \readonly
+
+    The type of the media element or \c MediaTypeNone if
+    the selected web page content is not a media element.
+
+    \value  ContextMenuRequest.MediaTypeNone
+            Not a media.
+    \value  ContextMenuRequest.MediaTypeImage
+            An image.
+    \value  ContextMenuRequest.MediaTypeVideo
+            A video.
+    \value  ContextMenuRequest.MediaTypeAudio
+            An audio element.
+    \value  ContextMenuRequest.MediaTypeCanvas
+            A canvas.
+    \value  ContextMenuRequest.MediaTypeFile
+            A file.
+    \value  ContextMenuRequest.MediaTypePlugin
+            A plugin.
+*/
+
+QQuickWebEngineContextMenuRequest::MediaType QQuickWebEngineContextMenuRequest::mediaType() const
+{
+    return static_cast<QQuickWebEngineContextMenuRequest::MediaType>(m_data->mediaType());
+}
+
+/*!
+    \qmlproperty bool ContextMenuRequest::isContentEditable
+    \readonly
+
+    Indicates whether the selected web content is editable.
+*/
+
+bool QQuickWebEngineContextMenuRequest::isContentEditable() const
+{
+    return m_data->isEditable();
+}
+
+/*!
+    \qmlproperty string ContextMenuRequest::misspelledWord
+    \readonly
+
+    If the context is a word considered misspelled by the spell-checker,
+    returns the misspelled word.
+*/
+
+QString QQuickWebEngineContextMenuRequest::misspelledWord() const
+{
+    return m_data->misspelledWord();
+}
+
+/*!
+    \qmlproperty stringlist ContextMenuRequest::spellCheckerSuggestions
+    \readonly
+
+    If the context is a word considered misspelled by the spell-checker,
+    returns a list of suggested replacements.
+*/
+
+QStringList QQuickWebEngineContextMenuRequest::spellCheckerSuggestions() const
+{
+    return m_data->spellCheckerSuggestions();
+}
+
+/*!
+    \qmlproperty bool ContextMenuRequest::accepted
+
+    Indicates whether the context menu request has been
+    handled by the signal handler.
+
+    If the property is \c false after any signal handlers
+    for WebEngineView::contextMenuRequested have been executed,
+    a default context menu will be shown.
+    To prevent this, set \c{request.accepted} to \c true.
+
+    The default is \c false.
+
+    \note The default content of the context menu depends on the
+    web element for which the request was actually generated.
+*/
+
+bool QQuickWebEngineContextMenuRequest::isAccepted() const
+{
+    return m_accepted;
+}
+
+void QQuickWebEngineContextMenuRequest::setAccepted(bool accepted)
+{
+    m_accepted = accepted;
+}
+
+QT_END_NAMESPACE
diff --git a/src/webengine/api/qquickwebenginecontextmenudata_p.h b/src/webengine/api/qquickwebenginecontextmenurequest_p.h
similarity index 57%
rename from src/webengine/api/qquickwebenginecontextmenudata_p.h
rename to src/webengine/api/qquickwebenginecontextmenurequest_p.h
index 7175838dbfde83a461a4e128055effda98970328..3d2de14a2cc1f49f27fa3f6d948164f26d8cc28e 100644
--- a/src/webengine/api/qquickwebenginecontextmenudata_p.h
+++ b/src/webengine/api/qquickwebenginecontextmenurequest_p.h
@@ -37,8 +37,8 @@
 **
 ****************************************************************************/
 
-#ifndef QQUICKWEBENGINECONTEXTMENUDATA_P_H
-#define QQUICKWEBENGINECONTEXTMENUDATA_P_H
+#ifndef QQUICKWEBENGINECONTEXTMENUREQUEST_H
+#define QQUICKWEBENGINECONTEXTMENUREQUEST_H
 
 //
 //  W A R N I N G
@@ -49,30 +49,21 @@
 // version without notice, or even be removed.
 //
 // We mean it.
-//
 
 #include <private/qtwebengineglobal_p.h>
+#include <QtCore/QScopedPointer>
 #include <QtCore/QObject>
-#include <QtCore/QPoint>
-#include <QtCore/QString>
 #include <QtCore/QUrl>
-#include <QtQuick/QQuickItem>
 
 namespace QtWebEngineCore {
-class WebEngineContextMenuData;
+    class WebEngineContextMenuData;
 }
 
 QT_BEGIN_NAMESPACE
 
-class QQuickWebEngineView;
-class QQuickWebEngineViewPrivate;
-
-class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineContextMenuData : public QObject {
+class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineContextMenuRequest: public QObject {
     Q_OBJECT
 public:
-    QQuickWebEngineContextMenuData();
-    ~QQuickWebEngineContextMenuData();
-
     enum MediaType {
         MediaTypeNone,
         MediaTypeImage,
@@ -84,56 +75,41 @@ public:
     };
     Q_ENUM(MediaType)
 
-    Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged)
-    Q_PROPERTY(QPoint position READ position NOTIFY positionChanged)
-    Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged)
-    Q_PROPERTY(QString linkText READ linkText NOTIFY linkTextChanged)
-    Q_PROPERTY(QUrl linkUrl READ linkUrl NOTIFY linkUrlChanged)
-    Q_PROPERTY(QUrl mediaUrl READ mediaUrl NOTIFY mediaUrlChanged)
-    Q_PROPERTY(MediaType mediaType READ mediaType NOTIFY mediaTypeChanged)
-    Q_PROPERTY(bool isContentEditable READ isContentEditable NOTIFY isContentEditableChanged)
-    Q_PROPERTY(QString misspelledWord READ misspelledWord NOTIFY misspelledWordChanged FINAL REVISION 1)
-    Q_PROPERTY(QStringList spellCheckerSuggestions READ spellCheckerSuggestions NOTIFY spellCheckerSuggestionsChanged FINAL REVISION 1)
-
-    bool isValid() const;
-
-    QPoint position() const;
+    Q_PROPERTY(int x READ x CONSTANT FINAL)
+    Q_PROPERTY(int y READ y CONSTANT FINAL)
+    Q_PROPERTY(QString selectedText READ selectedText CONSTANT FINAL)
+    Q_PROPERTY(QString linkText READ linkText CONSTANT FINAL)
+    Q_PROPERTY(QUrl linkUrl READ linkUrl CONSTANT FINAL)
+    Q_PROPERTY(QUrl mediaUrl READ mediaUrl CONSTANT FINAL)
+    Q_PROPERTY(MediaType mediaType READ mediaType CONSTANT FINAL)
+    Q_PROPERTY(bool isContentEditable READ isContentEditable CONSTANT FINAL)
+    Q_PROPERTY(QString misspelledWord READ misspelledWord CONSTANT FINAL)
+    Q_PROPERTY(QStringList spellCheckerSuggestions READ spellCheckerSuggestions CONSTANT FINAL)
+    Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted FINAL)
+
+    ~QQuickWebEngineContextMenuRequest();
+    int x() const;
+    int y() const;
     QString selectedText() const;
     QString linkText() const;
     QUrl linkUrl() const;
     QUrl mediaUrl() const;
     MediaType mediaType() const;
     bool isContentEditable() const;
-
     QString misspelledWord() const;
     QStringList spellCheckerSuggestions() const;
-
-Q_SIGNALS:
-    void isValidChanged();
-    void positionChanged();
-    void selectedTextChanged();
-    void linkTextChanged();
-    void linkUrlChanged();
-    void mediaUrlChanged();
-    void mediaTypeChanged();
-    void isContentEditableChanged();
-    Q_REVISION(1) void misspelledWordChanged();
-    Q_REVISION(1) void spellCheckerSuggestionsChanged();
+    bool isAccepted() const;
+    void setAccepted(bool accepted);
 
 private:
-    void update(const QtWebEngineCore::WebEngineContextMenuData &update);
-
+    QQuickWebEngineContextMenuRequest(const QtWebEngineCore::WebEngineContextMenuData &data, QObject *parent = nullptr);
+    QScopedPointer<QtWebEngineCore::WebEngineContextMenuData> m_data;
+    bool m_accepted;
     friend class QQuickWebEngineView;
     friend class QQuickWebEngineViewPrivate;
-    Q_DISABLE_COPY(QQuickWebEngineContextMenuData)
-    typedef QtWebEngineCore::WebEngineContextMenuData QQuickWebEngineContextMenuDataPrivate;
-    QQuickWebEngineContextMenuData(const QQuickWebEngineContextMenuDataPrivate *priv, QObject *parent = 0);
-    QQuickWebEngineContextMenuData &operator=(const QQuickWebEngineContextMenuDataPrivate *priv);
-    const QQuickWebEngineContextMenuDataPrivate *d;
+    Q_DISABLE_COPY(QQuickWebEngineContextMenuRequest)
 };
 
 QT_END_NAMESPACE
 
-QML_DECLARE_TYPE(const QQuickWebEngineContextMenuData);
-
-#endif // QQUICKWEBENGINECONTEXTMENUDATA_P_H
+#endif // QQUICKWEBENGINECONTEXTMENUREQUEST_H
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 968c9787a664fb87396965c81271feddfcc87f95..fd1e746a8e7d077266307af62f445e9ef62392db 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -47,6 +47,8 @@
 #include "javascript_dialog_controller.h"
 #include "qquickwebenginehistory_p.h"
 #include "qquickwebenginecertificateerror_p.h"
+#include "qquickwebenginecontextmenurequest_p.h"
+#include "qquickwebenginedialogrequests_p.h"
 #include "qquickwebenginefaviconprovider_p_p.h"
 #include "qquickwebengineloadrequest_p.h"
 #include "qquickwebenginenavigationrequest_p.h"
@@ -54,7 +56,6 @@
 #include "qquickwebengineprofile_p.h"
 #include "qquickwebenginesettings_p.h"
 #include "qquickwebenginescript_p_p.h"
-#include "qquickwebenginedialogrequests_p.h"
 
 #ifdef ENABLE_QML_TESTSUPPORT_API
 #include "qquickwebenginetestsupport_p.h"
@@ -234,34 +235,41 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
 {
     Q_Q(QQuickWebEngineView);
 
+    m_contextMenuData = data;
+
+    QQuickWebEngineContextMenuRequest *request = new QQuickWebEngineContextMenuRequest(data);
+    // mark the object for gc by creating temporary jsvalue
+    qmlEngine(q)->newQObject(request);
+    Q_EMIT q->contextMenuRequested(request);
+
+    if (request->isAccepted())
+        return true;
+
     // Assign the WebEngineView as the parent of the menu, so mouse events are properly propagated
     // on OSX.
-    QObject *menu = ui()->addMenu(q, QString(), data.pos);
+    QObject *menu = ui()->addMenu(q, QString(), data.position());
     if (!menu)
         return false;
 
-    contextMenuData.update(data);
-    Q_EMIT q->experimental()->contextMenuDataChanged();
-
     // Populate our menu
     MenuItemHandler *item = 0;
-    if (contextMenuData.isContentEditable() && !contextMenuData.spellCheckerSuggestions().isEmpty()) {
+    if (data.isEditable() && !data.spellCheckerSuggestions().isEmpty()) {
         const QPointer<QQuickWebEngineView> qRef(q);
-        for (int i=0; i < contextMenuData.spellCheckerSuggestions().count() && i < 4; i++) {
+        for (int i=0; i < data.spellCheckerSuggestions().count() && i < 4; i++) {
             item = new MenuItemHandler(menu);
-            QString replacement = contextMenuData.spellCheckerSuggestions().at(i);
+            QString replacement = data.spellCheckerSuggestions().at(i);
             QObject::connect(item, &MenuItemHandler::triggered, [qRef, replacement] { qRef->replaceMisspelledWord(replacement); });
             ui()->addMenuItem(item, replacement);
         }
         ui()->addMenuSeparator(menu);
     }
-    if (!data.linkText.isEmpty() && data.linkUrl.isValid()) {
+    if (!data.linkText().isEmpty() && data.linkUrl().isValid()) {
         item = new MenuItemHandler(menu);
         QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::OpenLinkInThisWindow); });
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Follow Link"));
     }
 
-    if (data.selectedText.isEmpty()) {
+    if (data.selectedText().isEmpty()) {
         item = new MenuItemHandler(menu);
         QObject::connect(item, &MenuItemHandler::triggered, q, &QQuickWebEngineView::goBack);
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Back"), QStringLiteral("go-previous"), q->canGoBack());
@@ -286,7 +294,7 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Unselect"));
     }
 
-    if (!contextMenuData.linkText().isEmpty() && contextMenuData.linkUrl().isValid()) {
+    if (!data.linkText().isEmpty() && data.linkUrl().isValid()) {
         item = new MenuItemHandler(menu);
         QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyLinkToClipboard); });
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Link URL"));
@@ -294,9 +302,9 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
         QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadLinkToDisk); });
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Save Link"));
     }
-    if (contextMenuData.mediaUrl().isValid()) {
-        switch (contextMenuData.mediaType()) {
-        case QQuickWebEngineContextMenuData::MediaTypeImage:
+    if (data.mediaUrl().isValid()) {
+        switch (data.mediaType()) {
+        case WebEngineContextMenuData::MediaTypeImage:
             item = new MenuItemHandler(menu);
             QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageUrlToClipboard); });
             ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Image URL"));
@@ -307,11 +315,11 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
             QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadImageToDisk); });
             ui()->addMenuItem(item, QQuickWebEngineView::tr("Save Image"));
             break;
-        case QQuickWebEngineContextMenuData::MediaTypeCanvas:
+        case WebEngineContextMenuData::MediaTypeCanvas:
             Q_UNREACHABLE();    // mediaUrl is invalid for canvases
             break;
-        case QQuickWebEngineContextMenuData::MediaTypeAudio:
-        case QQuickWebEngineContextMenuData::MediaTypeVideo:
+        case WebEngineContextMenuData::MediaTypeAudio:
+        case WebEngineContextMenuData::MediaTypeVideo:
             item = new MenuItemHandler(menu);
             QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyMediaUrlToClipboard); });
             ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Media URL"));
@@ -324,12 +332,12 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
             item = new MenuItemHandler(menu);
             QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaLoop); });
             ui()->addMenuItem(item, QQuickWebEngineView::tr("Toggle Looping"));
-            if (data.mediaFlags & WebEngineContextMenuData::MediaHasAudio) {
+            if (data.mediaFlags() & WebEngineContextMenuData::MediaHasAudio) {
                 item = new MenuItemHandler(menu);
                 QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaMute); });
                 ui()->addMenuItem(item, QQuickWebEngineView::tr("Toggle Mute"));
             }
-            if (data.mediaFlags & WebEngineContextMenuData::MediaCanToggleControls) {
+            if (data.mediaFlags() & WebEngineContextMenuData::MediaCanToggleControls) {
                 item = new MenuItemHandler(menu);
                 QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaControls); });
                 ui()->addMenuItem(item, QQuickWebEngineView::tr("Toggle Media Controls"));
@@ -338,7 +346,7 @@ bool QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
         default:
             break;
         }
-    } else if (contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeCanvas) {
+    } else if (data.mediaType() == WebEngineContextMenuData::MediaTypeCanvas) {
         item = new MenuItemHandler(menu);
         QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageToClipboard); });
         ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Image"));
@@ -1606,118 +1614,118 @@ void QQuickWebEngineView::triggerWebAction(WebAction action)
         d->adapter->unselect();
         break;
     case OpenLinkInThisWindow:
-        if (d->contextMenuData.linkUrl().isValid())
-            setUrl(d->contextMenuData.linkUrl());
+        if (d->m_contextMenuData.linkUrl().isValid())
+            setUrl(d->m_contextMenuData.linkUrl());
         break;
     case OpenLinkInNewWindow:
-        if (d->contextMenuData.linkUrl().isValid()) {
+        if (d->m_contextMenuData.linkUrl().isValid()) {
             QQuickWebEngineNewViewRequest request;
-            request.m_requestedUrl = d->contextMenuData.linkUrl();
+            request.m_requestedUrl = d->m_contextMenuData.linkUrl();
             request.m_isUserInitiated = true;
             request.m_destination = NewViewInWindow;
             Q_EMIT newViewRequested(&request);
         }
         break;
     case OpenLinkInNewTab:
-        if (d->contextMenuData.linkUrl().isValid()) {
+        if (d->m_contextMenuData.linkUrl().isValid()) {
             QQuickWebEngineNewViewRequest request;
-            request.m_requestedUrl = d->contextMenuData.linkUrl();
+            request.m_requestedUrl = d->m_contextMenuData.linkUrl();
             request.m_isUserInitiated = true;
             request.m_destination = NewViewInBackgroundTab;
             Q_EMIT newViewRequested(&request);
         }
         break;
     case CopyLinkToClipboard:
-        if (d->contextMenuData.linkUrl().isValid()) {
-            QString urlString = d->contextMenuData.linkUrl().toString(QUrl::FullyEncoded);
-            QString title = d->contextMenuData.linkText().toHtmlEscaped();
+        if (d->m_contextMenuData.linkUrl().isValid()) {
+            QString urlString = d->m_contextMenuData.linkUrl().toString(QUrl::FullyEncoded);
+            QString title = d->m_contextMenuData.linkText().toHtmlEscaped();
             QMimeData *data = new QMimeData();
             data->setText(urlString);
             QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>");
             data->setHtml(html);
-            data->setUrls(QList<QUrl>() << d->contextMenuData.linkUrl());
+            data->setUrls(QList<QUrl>() << d->m_contextMenuData.linkUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
     case DownloadLinkToDisk:
-        if (d->contextMenuData.linkUrl().isValid())
-            d->adapter->download(d->contextMenuData.linkUrl(), d->contextMenuData.d->suggestedFileName);
+        if (d->m_contextMenuData.linkUrl().isValid())
+            d->adapter->download(d->m_contextMenuData.linkUrl(), d->m_contextMenuData.suggestedFileName());
         break;
     case CopyImageToClipboard:
-        if (d->contextMenuData.d->hasImageContent &&
-                (d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeImage ||
-                 d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeCanvas))
+        if (d->m_contextMenuData.hasImageContent() &&
+                (d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeImage ||
+                 d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeCanvas))
         {
-            d->adapter->copyImageAt(d->contextMenuData.position());
+            d->adapter->copyImageAt(d->m_contextMenuData.position());
         }
         break;
     case CopyImageUrlToClipboard:
-        if (d->contextMenuData.mediaUrl().isValid() && d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeImage) {
-            QString urlString = d->contextMenuData.mediaUrl().toString(QUrl::FullyEncoded);
-            QString title = d->contextMenuData.linkText();
+        if (d->m_contextMenuData.mediaUrl().isValid() && d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeImage) {
+            QString urlString = d->m_contextMenuData.mediaUrl().toString(QUrl::FullyEncoded);
+            QString title = d->m_contextMenuData.linkText();
             if (!title.isEmpty())
                 title = QStringLiteral(" alt=\"%1\"").arg(title.toHtmlEscaped());
             QMimeData *data = new QMimeData();
             data->setText(urlString);
             QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral("></img>");
             data->setHtml(html);
-            data->setUrls(QList<QUrl>() << d->contextMenuData.mediaUrl());
+            data->setUrls(QList<QUrl>() << d->m_contextMenuData.mediaUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
     case DownloadImageToDisk:
     case DownloadMediaToDisk:
-        if (d->contextMenuData.mediaUrl().isValid())
-            d->adapter->download(d->contextMenuData.mediaUrl(), d->contextMenuData.d->suggestedFileName);
+        if (d->m_contextMenuData.mediaUrl().isValid())
+            d->adapter->download(d->m_contextMenuData.mediaUrl(), d->m_contextMenuData.suggestedFileName());
         break;
     case CopyMediaUrlToClipboard:
-        if (d->contextMenuData.mediaUrl().isValid() &&
-                (d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeAudio ||
-                 d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeVideo))
+        if (d->m_contextMenuData.mediaUrl().isValid() &&
+                (d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio ||
+                 d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeVideo))
         {
-            QString urlString = d->contextMenuData.mediaUrl().toString(QUrl::FullyEncoded);
+            QString urlString = d->m_contextMenuData.mediaUrl().toString(QUrl::FullyEncoded);
             QMimeData *data = new QMimeData();
             data->setText(urlString);
-            if (d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeAudio)
+            if (d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio)
                 data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"></audio>"));
             else
                 data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"></video>"));
-            data->setUrls(QList<QUrl>() << d->contextMenuData.mediaUrl());
+            data->setUrls(QList<QUrl>() << d->m_contextMenuData.mediaUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
     case ToggleMediaControls:
-        if (d->contextMenuData.mediaUrl().isValid() && d->contextMenuData.d->mediaFlags & WebEngineContextMenuData::MediaCanToggleControls) {
-            bool enable = !(d->contextMenuData.d->mediaFlags & WebEngineContextMenuData::MediaControls);
-            d->adapter->executeMediaPlayerActionAt(d->contextMenuData.position(), WebContentsAdapter::MediaPlayerControls, enable);
+        if (d->m_contextMenuData.mediaUrl().isValid() && d->m_contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaCanToggleControls) {
+            bool enable = !(d->m_contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaControls);
+            d->adapter->executeMediaPlayerActionAt(d->m_contextMenuData.position(), WebContentsAdapter::MediaPlayerControls, enable);
         }
         break;
     case ToggleMediaLoop:
-        if (d->contextMenuData.mediaUrl().isValid() &&
-                (d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeAudio ||
-                 d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeVideo))
+        if (d->m_contextMenuData.mediaUrl().isValid() &&
+                (d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio ||
+                 d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeVideo))
         {
-            bool enable = !(d->contextMenuData.d->mediaFlags & WebEngineContextMenuData::MediaLoop);
-            d->adapter->executeMediaPlayerActionAt(d->contextMenuData.position(), WebContentsAdapter::MediaPlayerLoop, enable);
+            bool enable = !(d->m_contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaLoop);
+            d->adapter->executeMediaPlayerActionAt(d->m_contextMenuData.position(), WebContentsAdapter::MediaPlayerLoop, enable);
         }
         break;
     case ToggleMediaPlayPause:
-        if (d->contextMenuData.mediaUrl().isValid() &&
-                (d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeAudio ||
-                 d->contextMenuData.mediaType() == QQuickWebEngineContextMenuData::MediaTypeVideo))
+        if (d->m_contextMenuData.mediaUrl().isValid() &&
+                (d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio ||
+                 d->m_contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeVideo))
         {
-            bool enable = (d->contextMenuData.d->mediaFlags & WebEngineContextMenuData::MediaPaused);
-            d->adapter->executeMediaPlayerActionAt(d->contextMenuData.position(), WebContentsAdapter::MediaPlayerPlay, enable);
+            bool enable = (d->m_contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaPaused);
+            d->adapter->executeMediaPlayerActionAt(d->m_contextMenuData.position(), WebContentsAdapter::MediaPlayerPlay, enable);
         }
         break;
     case ToggleMediaMute:
-        if (d->contextMenuData.mediaUrl().isValid() && d->contextMenuData.d->mediaFlags & WebEngineContextMenuData::MediaHasAudio) {
-            bool enable = !(d->contextMenuData.d->mediaFlags & WebEngineContextMenuData::MediaMuted);
-            d->adapter->executeMediaPlayerActionAt(d->contextMenuData.position(), WebContentsAdapter::MediaPlayerMute, enable);
+        if (d->m_contextMenuData.mediaUrl().isValid() && d->m_contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaHasAudio) {
+            bool enable = !(d->m_contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaMuted);
+            d->adapter->executeMediaPlayerActionAt(d->m_contextMenuData.position(), WebContentsAdapter::MediaPlayerMute, enable);
         }
         break;
     case InspectElement:
-        d->adapter->inspectElementAt(d->contextMenuData.position());
+        d->adapter->inspectElementAt(d->m_contextMenuData.position());
         break;
     case ExitFullScreen:
         d->adapter->exitFullScreen();
@@ -1733,12 +1741,6 @@ void QQuickWebEngineView::triggerWebAction(WebAction action)
     }
 }
 
-const QQuickWebEngineContextMenuData *QQuickWebEngineViewExperimental::contextMenuData() const
-{
-    Q_D(const QQuickWebEngineView);
-    return &d->contextMenuData;
-}
-
 QSizeF QQuickWebEngineView::contentsSize() const
 {
     Q_D(const QQuickWebEngineView);
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index 99d0848ceea4bb84463da16559dc0838c26fe661..1d44a48dd217aa9f3759db74b7920c2e3f5a5a02 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -62,7 +62,7 @@ class QQmlWebChannel;
 class QQuickWebEngineAuthenticationDialogRequest;
 class QQuickWebEngineCertificateError;
 class QQuickWebEngineColorDialogRequest;
-class QQuickWebEngineContextMenuData;
+class QQuickWebEngineContextMenuRequest;
 class QQuickWebEngineFaviconProvider;
 class QQuickWebEngineFileDialogRequest;
 class QQuickWebEngineHistory;
@@ -511,7 +511,7 @@ Q_SIGNALS:
     Q_REVISION(3) void audioMutedChanged(bool muted);
     Q_REVISION(3) void recentlyAudibleChanged(bool recentlyAudible);
     Q_REVISION(3) void webChannelWorldChanged(uint);
-
+    Q_REVISION(4) void contextMenuRequested(QQuickWebEngineContextMenuRequest *request);
     Q_REVISION(4) void authenticationDialogRequested(QQuickWebEngineAuthenticationDialogRequest *request);
     Q_REVISION(4) void javaScriptDialogRequested(QQuickWebEngineJavaScriptDialogRequest *request);
     Q_REVISION(4) void colorDialogRequested(QQuickWebEngineColorDialogRequest *request);
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 3ba1f8ae12d42fbd836ed4861e6c6ad9111110f2..c6ff1837324f2659852fa8a318b0c002566771a5 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -52,7 +52,6 @@
 //
 
 #include "qquickwebengineview_p.h"
-#include "qquickwebenginecontextmenudata_p.h"
 #include "web_contents_adapter_client.h"
 
 #include <QScopedPointer>
@@ -70,6 +69,7 @@ QT_BEGIN_NAMESPACE
 class QQuickWebEngineView;
 class QQmlComponent;
 class QQmlContext;
+class QQuickWebEngineContextMenuRequest;
 class QQuickWebEngineSettings;
 class QQuickWebEngineFaviconProvider;
 
@@ -101,17 +101,13 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewExperimental : public QObjec
     Q_OBJECT
     Q_PROPERTY(QQuickWebEngineViewport *viewport READ viewport)
     Q_PROPERTY(QQmlComponent *extraContextMenuEntriesComponent READ extraContextMenuEntriesComponent WRITE setExtraContextMenuEntriesComponent NOTIFY extraContextMenuEntriesComponentChanged)
-    Q_PROPERTY(const QQuickWebEngineContextMenuData *contextMenuData READ contextMenuData NOTIFY contextMenuDataChanged)
 
     QQuickWebEngineViewport *viewport() const;
     void setExtraContextMenuEntriesComponent(QQmlComponent *);
     QQmlComponent *extraContextMenuEntriesComponent() const;
 
-    const QQuickWebEngineContextMenuData *contextMenuData() const;
-
 Q_SIGNALS:
     void extraContextMenuEntriesComponentChanged();
-    void contextMenuDataChanged();
 
 private:
     QQuickWebEngineViewExperimental(QQuickWebEngineViewPrivate* viewPrivate);
@@ -221,7 +217,7 @@ public:
     QQuickWebEngineTestSupport *m_testSupport;
 #endif
     QQmlComponent *contextMenuExtraItems;
-    QQuickWebEngineContextMenuData contextMenuData;
+    QtWebEngineCore::WebEngineContextMenuData m_contextMenuData;
     QUrl explicitUrl;
     QUrl iconUrl;
     QQuickWebEngineFaviconProvider *faviconProvider;
diff --git a/src/webengine/doc/src/webengineview.qdoc b/src/webengine/doc/src/webengineview.qdoc
index eaf7936d263e248162262f5dab26ee3d18846c27..4acf3eb55f56a86b284a51a2d12e7d2c00034f90 100644
--- a/src/webengine/doc/src/webengineview.qdoc
+++ b/src/webengine/doc/src/webengineview.qdoc
@@ -1231,3 +1231,16 @@
     \note Signal handlers need to call \c{request.accepted = true} to prevent a
     default dialog from showing up.
 */
+
+/*!
+    \qmlsignal WebEngineView::contextMenuRequested(ContextMenuRequest request)
+    \since QtWebEngine 1.4
+
+    This signal is emitted when a context menu is requested.
+
+    The request can be handled by using the properties of the ContextMenuRequest
+    type.
+
+    \note Signal handlers need to call \c{request.accepted = true} to prevent a
+    default context menu from showing up.
+*/
diff --git a/src/webengine/plugin/experimental/plugin.cpp b/src/webengine/plugin/experimental/plugin.cpp
index d4f68d142d6be4c00ebf76560ec119c0244fcc32..23a81d79d10a1fa0464a03d4fc63a208f6ca461f 100644
--- a/src/webengine/plugin/experimental/plugin.cpp
+++ b/src/webengine/plugin/experimental/plugin.cpp
@@ -41,7 +41,6 @@
 
 #include "qquickwebengineview_p.h"
 #include "qquickwebengineview_p_p.h"
-#include "qquickwebenginecontextmenudata_p.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -70,10 +69,6 @@ public:
             tr("Cannot create a separate instance of WebEngineViewExperimental"));
         qmlRegisterUncreatableType<QQuickWebEngineViewport>(uri, 1, 0, "WebEngineViewport",
             tr("Cannot create a separate instance of WebEngineViewport"));
-        qmlRegisterUncreatableType<const QQuickWebEngineContextMenuData>(uri, 1, 0, "WebEngineContextMenuData",
-            tr("Cannot create a separate instance of WebEngineContextMenuData"));
-        qmlRegisterUncreatableType<const QQuickWebEngineContextMenuData, 1>(uri, 1, 1, "WebEngineContextMenuData",
-            tr("Cannot create a separate instance of WebEngineContextMenuData"));
         // Use the latest revision of QQuickWebEngineView when importing QtWebEngine.experimental 1.0
         qmlRegisterRevision<QQuickWebEngineView, LATEST_WEBENGINEVIEW_REVISION>(uri, 1, 1);
     }
diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp
index 0bf2e3d8e8bd97725493629d5223be2c1194d24c..d3f3712b4a7dc405fc7c77c17465beb15cfb174f 100644
--- a/src/webengine/plugin/plugin.cpp
+++ b/src/webengine/plugin/plugin.cpp
@@ -41,6 +41,7 @@
 #include <QtWebEngine/QQuickWebEngineProfile>
 
 #include "qquickwebenginecertificateerror_p.h"
+#include "qquickwebenginecontextmenurequest_p.h"
 #include "qquickwebenginedialogrequests_p.h"
 #include "qquickwebenginedownloaditem_p.h"
 #include "qquickwebenginehistory_p.h"
@@ -110,6 +111,8 @@ public:
         qmlRegisterUncreatableType<QQuickWebEngineFullScreenRequest>(uri, 1, 1, "FullScreenRequest",
             tr("Cannot create a separate instance of FullScreenRequest"));
 
+        qmlRegisterUncreatableType<QQuickWebEngineContextMenuRequest>(uri, 1, 4, "ContextMenuRequest",
+                                                                    tr("Cannot create separate instance of ContextMenuRequest"));
         qmlRegisterUncreatableType<QQuickWebEngineAuthenticationDialogRequest>(uri, 1, 4, "AuthenticationDialogRequest",
                                                                        tr("Cannot create separate instance of AuthenticationDialogRequest"));
         qmlRegisterUncreatableType<QQuickWebEngineJavaScriptDialogRequest>(uri, 1, 4, "JavaScriptDialogRequest",
diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro
index 1b361d6ae35b508e40fb07b605934fb1b3a510cd..e84188682a0d0bd6b738689f8869744b92633816 100644
--- a/src/webengine/webengine.pro
+++ b/src/webengine/webengine.pro
@@ -12,7 +12,7 @@ INCLUDEPATH += $$PWD api ../core ../core/api
 
 SOURCES = \
         api/qquickwebenginecertificateerror.cpp \
-        api/qquickwebenginecontextmenudata.cpp \
+        api/qquickwebenginecontextmenurequest.cpp \
         api/qquickwebenginedialogrequests.cpp \
         api/qquickwebenginedownloaditem.cpp \
         api/qquickwebenginehistory.cpp \
@@ -34,7 +34,7 @@ HEADERS = \
         api/qtwebengineglobal.h \
         api/qtwebengineglobal_p.h \
         api/qquickwebenginecertificateerror_p.h \
-        api/qquickwebenginecontextmenudata_p.h \
+        api/qquickwebenginecontextmenurequest_p.h \
         api/qquickwebenginedialogrequests_p.h \
         api/qquickwebenginedownloaditem_p.h \
         api/qquickwebenginedownloaditem_p_p.h \
diff --git a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
index 808c6f8b055b03078290a21d0f164a145bd13663..23be32bf6edafe841a4e8df279d6cfcb726410ec 100644
--- a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
+++ b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
@@ -135,7 +135,7 @@ void QWebEngineContextMenuData::reset()
 */
 QPoint QWebEngineContextMenuData::position() const
 {
-    return d ? d->pos : QPoint();
+    return d ? d->position() : QPoint();
 }
 
 /*!
@@ -143,7 +143,7 @@ QPoint QWebEngineContextMenuData::position() const
 */
 QString QWebEngineContextMenuData::linkText() const
 {
-    return d ? d->linkText : QString();
+    return d ? d->linkText() : QString();
 }
 
 /*!
@@ -151,7 +151,7 @@ QString QWebEngineContextMenuData::linkText() const
 */
 QUrl QWebEngineContextMenuData::linkUrl() const
 {
-    return d ? d->linkUrl : QUrl();
+    return d ? d->linkUrl() : QUrl();
 }
 
 /*!
@@ -159,7 +159,7 @@ QUrl QWebEngineContextMenuData::linkUrl() const
 */
 QString QWebEngineContextMenuData::selectedText() const
 {
-    return d ? d->selectedText : QString();
+    return d ? d->selectedText() : QString();
 }
 
 /*!
@@ -167,7 +167,7 @@ QString QWebEngineContextMenuData::selectedText() const
 */
 QUrl QWebEngineContextMenuData::mediaUrl() const
 {
-    return d ? d->mediaUrl : QUrl();
+    return d ? d->mediaUrl() : QUrl();
 }
 
 /*!
@@ -175,7 +175,7 @@ QUrl QWebEngineContextMenuData::mediaUrl() const
 */
 QWebEngineContextMenuData::MediaType QWebEngineContextMenuData::mediaType() const
 {
-    return d ? static_cast<QWebEngineContextMenuData::MediaType>(d->mediaType) : MediaTypeNone;
+    return d ? static_cast<QWebEngineContextMenuData::MediaType>(d->mediaType()) : MediaTypeNone;
 }
 
 /*!
@@ -183,7 +183,7 @@ QWebEngineContextMenuData::MediaType QWebEngineContextMenuData::mediaType() cons
 */
 bool QWebEngineContextMenuData::isContentEditable() const
 {
-    return d ? d->isEditable : false;
+    return d ? d->isEditable() : false;
 }
 
 /*!
@@ -194,7 +194,7 @@ bool QWebEngineContextMenuData::isContentEditable() const
 QString QWebEngineContextMenuData::misspelledWord() const
 {
     if (d)
-        return d->misspelledWord;
+        return d->misspelledWord();
     return QString();
 }
 
@@ -206,7 +206,7 @@ QString QWebEngineContextMenuData::misspelledWord() const
 QStringList QWebEngineContextMenuData::spellCheckerSuggestions() const
 {
     if (d)
-        return d->spellCheckerSuggestions;
+        return d->spellCheckerSuggestions();
     return QStringList();
 }
 
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index ae933f01b7d1a2c84c1f660ffdc7fc42af0d0d28..37c156e1733a65f04ea3fe7d0702a4facba17d70 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -1056,122 +1056,122 @@ void QWebEnginePage::triggerAction(WebAction action, bool)
         d->adapter->unselect();
         break;
     case OpenLinkInThisWindow:
-        if (menuData.linkUrl.isValid())
-            setUrl(menuData.linkUrl);
+        if (menuData.linkUrl().isValid())
+            setUrl(menuData.linkUrl());
         break;
     case OpenLinkInNewWindow:
-        if (menuData.linkUrl.isValid()) {
+        if (menuData.linkUrl().isValid()) {
             QWebEnginePage *newPage = createWindow(WebBrowserWindow);
             if (newPage)
-                newPage->setUrl(menuData.linkUrl);
+                newPage->setUrl(menuData.linkUrl());
         }
         break;
     case OpenLinkInNewTab:
-        if (menuData.linkUrl.isValid()) {
+        if (menuData.linkUrl().isValid()) {
             QWebEnginePage *newPage = createWindow(WebBrowserTab);
             if (newPage)
-                newPage->setUrl(menuData.linkUrl);
+                newPage->setUrl(menuData.linkUrl());
         }
         break;
     case OpenLinkInNewBackgroundTab:
-        if (menuData.linkUrl.isValid()) {
+        if (menuData.linkUrl().isValid()) {
             QWebEnginePage *newPage = createWindow(WebBrowserBackgroundTab);
             if (newPage)
-                newPage->setUrl(menuData.linkUrl);
+                newPage->setUrl(menuData.linkUrl());
         }
         break;
     case CopyLinkToClipboard:
-        if (menuData.linkUrl.isValid()) {
-            QString urlString = menuData.linkUrl.toString(QUrl::FullyEncoded);
-            QString title = menuData.linkText.toHtmlEscaped();
+        if (menuData.linkUrl().isValid()) {
+            QString urlString = menuData.linkUrl().toString(QUrl::FullyEncoded);
+            QString title = menuData.linkText().toHtmlEscaped();
             QMimeData *data = new QMimeData();
             data->setText(urlString);
             QString html = QStringLiteral("<a href=\"") + urlString + QStringLiteral("\">") + title + QStringLiteral("</a>");
             data->setHtml(html);
-            data->setUrls(QList<QUrl>() << menuData.linkUrl);
+            data->setUrls(QList<QUrl>() << menuData.linkUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
     case DownloadLinkToDisk:
-        if (menuData.linkUrl.isValid())
-            d->adapter->download(menuData.linkUrl, menuData.suggestedFileName);
+        if (menuData.linkUrl().isValid())
+            d->adapter->download(menuData.linkUrl(), menuData.suggestedFileName());
         break;
     case CopyImageToClipboard:
-        if (menuData.hasImageContent &&
-                (menuData.mediaType == WebEngineContextMenuData::MediaTypeImage ||
-                 menuData.mediaType == WebEngineContextMenuData::MediaTypeCanvas))
+        if (menuData.hasImageContent() &&
+                (menuData.mediaType() == WebEngineContextMenuData::MediaTypeImage ||
+                 menuData.mediaType() == WebEngineContextMenuData::MediaTypeCanvas))
         {
-            d->adapter->copyImageAt(menuData.pos);
+            d->adapter->copyImageAt(menuData.position());
         }
         break;
     case CopyImageUrlToClipboard:
-        if (menuData.mediaUrl.isValid() && menuData.mediaType == WebEngineContextMenuData::MediaTypeImage) {
-            QString urlString = menuData.mediaUrl.toString(QUrl::FullyEncoded);
-            QString title = menuData.linkText;
+        if (menuData.mediaUrl().isValid() && menuData.mediaType() == WebEngineContextMenuData::MediaTypeImage) {
+            QString urlString = menuData.mediaUrl().toString(QUrl::FullyEncoded);
+            QString title = menuData.linkText();
             if (!title.isEmpty())
                 title = QStringLiteral(" alt=\"%1\"").arg(title.toHtmlEscaped());
             QMimeData *data = new QMimeData();
             data->setText(urlString);
             QString html = QStringLiteral("<img src=\"") + urlString + QStringLiteral("\"") + title + QStringLiteral("></img>");
             data->setHtml(html);
-            data->setUrls(QList<QUrl>() << menuData.mediaUrl);
+            data->setUrls(QList<QUrl>() << menuData.mediaUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
     case DownloadImageToDisk:
     case DownloadMediaToDisk:
-        if (menuData.mediaUrl.isValid())
-            d->adapter->download(menuData.mediaUrl, menuData.suggestedFileName);
+        if (menuData.mediaUrl().isValid())
+            d->adapter->download(menuData.mediaUrl(), menuData.suggestedFileName());
         break;
     case CopyMediaUrlToClipboard:
-        if (menuData.mediaUrl.isValid() &&
-                (menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio ||
-                 menuData.mediaType == WebEngineContextMenuData::MediaTypeVideo))
+        if (menuData.mediaUrl().isValid() &&
+                (menuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio ||
+                 menuData.mediaType() == WebEngineContextMenuData::MediaTypeVideo))
         {
-            QString urlString = menuData.mediaUrl.toString(QUrl::FullyEncoded);
+            QString urlString = menuData.mediaUrl().toString(QUrl::FullyEncoded);
             QMimeData *data = new QMimeData();
             data->setText(urlString);
-            if (menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio)
+            if (menuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio)
                 data->setHtml(QStringLiteral("<audio src=\"") + urlString + QStringLiteral("\"></audio>"));
             else
                 data->setHtml(QStringLiteral("<video src=\"") + urlString + QStringLiteral("\"></video>"));
-            data->setUrls(QList<QUrl>() << menuData.mediaUrl);
+            data->setUrls(QList<QUrl>() << menuData.mediaUrl());
             qApp->clipboard()->setMimeData(data);
         }
         break;
     case ToggleMediaControls:
-        if (menuData.mediaUrl.isValid() && menuData.mediaFlags & WebEngineContextMenuData::MediaCanToggleControls) {
-            bool enable = !(menuData.mediaFlags & WebEngineContextMenuData::MediaControls);
-            d->adapter->executeMediaPlayerActionAt(menuData.pos, WebContentsAdapter::MediaPlayerControls, enable);
+        if (menuData.mediaUrl().isValid() && menuData.mediaFlags() & WebEngineContextMenuData::MediaCanToggleControls) {
+            bool enable = !(menuData.mediaFlags() & WebEngineContextMenuData::MediaControls);
+            d->adapter->executeMediaPlayerActionAt(menuData.position(), WebContentsAdapter::MediaPlayerControls, enable);
         }
         break;
     case ToggleMediaLoop:
-        if (menuData.mediaUrl.isValid() &&
-                (menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio ||
-                 menuData.mediaType == WebEngineContextMenuData::MediaTypeVideo))
+        if (menuData.mediaUrl().isValid() &&
+                (menuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio ||
+                 menuData.mediaType() == WebEngineContextMenuData::MediaTypeVideo))
         {
-            bool enable = !(menuData.mediaFlags & WebEngineContextMenuData::MediaLoop);
-            d->adapter->executeMediaPlayerActionAt(menuData.pos, WebContentsAdapter::MediaPlayerLoop, enable);
+            bool enable = !(menuData.mediaFlags() & WebEngineContextMenuData::MediaLoop);
+            d->adapter->executeMediaPlayerActionAt(menuData.position(), WebContentsAdapter::MediaPlayerLoop, enable);
         }
         break;
     case ToggleMediaPlayPause:
-        if (menuData.mediaUrl.isValid() &&
-                (menuData.mediaType == WebEngineContextMenuData::MediaTypeAudio ||
-                 menuData.mediaType == WebEngineContextMenuData::MediaTypeVideo))
+        if (menuData.mediaUrl().isValid() &&
+                (menuData.mediaType() == WebEngineContextMenuData::MediaTypeAudio ||
+                 menuData.mediaType() == WebEngineContextMenuData::MediaTypeVideo))
         {
-            bool enable = (menuData.mediaFlags & WebEngineContextMenuData::MediaPaused);
-            d->adapter->executeMediaPlayerActionAt(menuData.pos, WebContentsAdapter::MediaPlayerPlay, enable);
+            bool enable = (menuData.mediaFlags() & WebEngineContextMenuData::MediaPaused);
+            d->adapter->executeMediaPlayerActionAt(menuData.position(), WebContentsAdapter::MediaPlayerPlay, enable);
         }
         break;
     case ToggleMediaMute:
-        if (menuData.mediaUrl.isValid() && menuData.mediaFlags & WebEngineContextMenuData::MediaHasAudio) {
+        if (menuData.mediaUrl().isValid() && menuData.mediaFlags() & WebEngineContextMenuData::MediaHasAudio) {
             // Make sure to negate the value, so that toggling actually works.
-            bool enable = !(menuData.mediaFlags & WebEngineContextMenuData::MediaMuted);
-            d->adapter->executeMediaPlayerActionAt(menuData.pos, WebContentsAdapter::MediaPlayerMute, enable);
+            bool enable = !(menuData.mediaFlags() & WebEngineContextMenuData::MediaMuted);
+            d->adapter->executeMediaPlayerActionAt(menuData.position(), WebContentsAdapter::MediaPlayerMute, enable);
         }
         break;
     case InspectElement:
-        d->adapter->inspectElementAt(menuData.pos);
+        d->adapter->inspectElementAt(menuData.position());
         break;
     case ExitFullScreen:
         d->adapter->exitFullScreen();
@@ -1253,7 +1253,7 @@ bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData
         return false;
 
     contextData.reset();
-    QContextMenuEvent event(QContextMenuEvent::Mouse, data.pos, view->mapToGlobal(data.pos));
+    QContextMenuEvent event(QContextMenuEvent::Mouse, data.position(), view->mapToGlobal(data.position()));
     switch (view->contextMenuPolicy()) {
     case Qt::PreventContextMenu:
         return false;
@@ -1263,7 +1263,7 @@ bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData
         break;
     case Qt::CustomContextMenu:
         contextData = data;
-        Q_EMIT view->customContextMenuRequested(data.pos);
+        Q_EMIT view->customContextMenuRequested(data.position());
         break;
     case Qt::ActionsContextMenu:
         if (view->actions().count()) {
@@ -1418,11 +1418,11 @@ QMenu *QWebEnginePage::createStandardContextMenu()
     QAction *action = 0;
     const WebEngineContextMenuData &contextMenuData = *d->contextData.d;
 
-    if (contextMenuData.isEditable && !contextMenuData.spellCheckerSuggestions.isEmpty()) {
+    if (contextMenuData.isEditable() && !contextMenuData.spellCheckerSuggestions().isEmpty()) {
         QPointer<QWebEnginePage> thisRef(this);
-        for (int i=0; i < contextMenuData.spellCheckerSuggestions.count() && i < 4; i++) {
+        for (int i=0; i < contextMenuData.spellCheckerSuggestions().count() && i < 4; i++) {
             QAction *action = new QAction(menu);
-            QString replacement = contextMenuData.spellCheckerSuggestions.at(i);
+            QString replacement = contextMenuData.spellCheckerSuggestions().at(i);
             QObject::connect(action, &QAction::triggered, [thisRef, replacement] { if (thisRef) thisRef->replaceMisspelledWord(replacement); });
             action->setText(replacement);
             menu->addAction(action);
@@ -1430,13 +1430,13 @@ QMenu *QWebEnginePage::createStandardContextMenu()
         menu->addSeparator();
     }
 
-    if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) {
+    if (!contextMenuData.linkText().isEmpty() && contextMenuData.linkUrl().isValid()) {
         action = QWebEnginePage::action(OpenLinkInThisWindow);
         action->setText(tr("Follow Link"));
         menu->addAction(action);
         menu->addAction(QWebEnginePage::action(DownloadLinkToDisk));
     }
-    if (contextMenuData.selectedText.isEmpty()) {
+    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());
@@ -1457,11 +1457,11 @@ QMenu *QWebEnginePage::createStandardContextMenu()
         menu->addAction(QWebEnginePage::action(Unselect));
     }
 
-    if (!contextMenuData.linkText.isEmpty() && contextMenuData.linkUrl.isValid()) {
+    if (!contextMenuData.linkText().isEmpty() && contextMenuData.linkUrl().isValid()) {
         menu->addAction(QWebEnginePage::action(CopyLinkToClipboard));
     }
-    if (contextMenuData.mediaUrl.isValid()) {
-        switch (contextMenuData.mediaType) {
+    if (contextMenuData.mediaUrl().isValid()) {
+        switch (contextMenuData.mediaType()) {
         case WebEngineContextMenuData::MediaTypeImage:
             menu->addAction(QWebEnginePage::action(DownloadImageToDisk));
             menu->addAction(QWebEnginePage::action(CopyImageUrlToClipboard));
@@ -1476,15 +1476,15 @@ QMenu *QWebEnginePage::createStandardContextMenu()
             menu->addAction(QWebEnginePage::action(CopyMediaUrlToClipboard));
             menu->addAction(QWebEnginePage::action(ToggleMediaPlayPause));
             menu->addAction(QWebEnginePage::action(ToggleMediaLoop));
-            if (contextMenuData.mediaFlags & WebEngineContextMenuData::MediaHasAudio)
+            if (contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaHasAudio)
                 menu->addAction(QWebEnginePage::action(ToggleMediaMute));
-            if (contextMenuData.mediaFlags & WebEngineContextMenuData::MediaCanToggleControls)
+            if (contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaCanToggleControls)
                 menu->addAction(QWebEnginePage::action(ToggleMediaControls));
             break;
         default:
             break;
         }
-    } else if (contextMenuData.mediaType == WebEngineContextMenuData::MediaTypeCanvas) {
+    } else if (contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeCanvas) {
         menu->addAction(QWebEnginePage::action(CopyImageToClipboard));
     }
 
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index 92a96273c41d8ea97d0eb95abcda02e168d04b64..f9fd854ccbbd692f04cbca96c99e9a372beb0f16 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -45,6 +45,7 @@
 #include <private/qquickwebenginescript_p.h>
 #include <private/qquickwebenginesettings_p.h>
 #include <private/qquickwebenginesingleton_p.h>
+#include <private/qquickwebenginecontextmenurequest_p.h>
 
 class tst_publicapi : public QObject {
     Q_OBJECT
@@ -71,6 +72,7 @@ static QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *>()
     << &QQuickWebEngineColorDialogRequest::staticMetaObject
     << &QQuickWebEngineFileDialogRequest::staticMetaObject
     << &QQuickWebEngineFormValidationMessageRequest::staticMetaObject
+    << &QQuickWebEngineContextMenuRequest::staticMetaObject
     ;
 
 static QList<const char *> knownEnumNames = QList<const char *>();