summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/webengine/minimal/doc/src/minimal.qdoc7
-rw-r--r--examples/webengine/minimal/main.cpp2
-rw-r--r--examples/webengine/quicknanobrowser/main.cpp2
-rw-r--r--examples/webenginewidgets/contentmanipulation/main.cpp1
-rw-r--r--examples/webenginewidgets/cookiebrowser/main.cpp1
-rw-r--r--examples/webenginewidgets/demobrowser/history.cpp10
-rw-r--r--examples/webenginewidgets/demobrowser/history.h2
-rw-r--r--examples/webenginewidgets/demobrowser/main.cpp1
-rw-r--r--examples/webenginewidgets/markdowneditor/main.cpp1
-rw-r--r--examples/webenginewidgets/minimal/doc/src/minimal.qdoc5
-rw-r--r--examples/webenginewidgets/minimal/main.cpp1
-rw-r--r--examples/webenginewidgets/simplebrowser/main.cpp2
-rw-r--r--src/core/gyp_run.pro13
-rw-r--r--src/core/render_widget_host_view_qt.cpp87
-rw-r--r--src/core/render_widget_host_view_qt.h1
-rw-r--r--src/core/web_event_factory.cpp11
-rw-r--r--src/webengine/api/qquickwebengineview.cpp36
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h2
-rw-r--r--src/webengine/doc/src/qtwebengine-index.qdoc4
-rw-r--r--src/webengine/doc/src/qtwebengine-qmlmodule.qdoc2
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.cpp12
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quick.h1
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp36
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h2
-rw-r--r--src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp7
-rw-r--r--tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp31
26 files changed, 238 insertions, 42 deletions
diff --git a/examples/webengine/minimal/doc/src/minimal.qdoc b/examples/webengine/minimal/doc/src/minimal.qdoc
index c0b89ba5a..5d7ca45e7 100644
--- a/examples/webengine/minimal/doc/src/minimal.qdoc
+++ b/examples/webengine/minimal/doc/src/minimal.qdoc
@@ -50,8 +50,11 @@
\skipto #include
\printto main
- In the main function we first instantiate a QGuiApplication object.
- We then call \l{QtWebEngine::initialize}, which makes sure that OpenGL
+ In the \c main function we first set the Qt::AA_EnableHighDpiScaling
+ attribute. This lets the web view automatically scale on high-dpi displays.
+ Then we instantiate a QGuiApplication object.
+
+ Next, we call \l{QtWebEngine::initialize}, which makes sure that OpenGL
contexts can be shared between the main process and the dedicated renderer
process (\c QtWebEngineProcess). This method needs to be called before
any OpenGL context is created.
diff --git a/examples/webengine/minimal/main.cpp b/examples/webengine/minimal/main.cpp
index cc5a1f61e..099b70707 100644
--- a/examples/webengine/minimal/main.cpp
+++ b/examples/webengine/minimal/main.cpp
@@ -44,7 +44,9 @@
int main(int argc, char *argv[])
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
+
QtWebEngine::initialize();
QQmlApplicationEngine engine;
diff --git a/examples/webengine/quicknanobrowser/main.cpp b/examples/webengine/quicknanobrowser/main.cpp
index 779648fac..94d6f8519 100644
--- a/examples/webengine/quicknanobrowser/main.cpp
+++ b/examples/webengine/quicknanobrowser/main.cpp
@@ -78,6 +78,8 @@ static QUrl startupUrl()
int main(int argc, char **argv)
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
Application app(argc, argv);
QtWebEngine::initialize();
diff --git a/examples/webenginewidgets/contentmanipulation/main.cpp b/examples/webenginewidgets/contentmanipulation/main.cpp
index 9f2f2f736..5645f9b9a 100644
--- a/examples/webenginewidgets/contentmanipulation/main.cpp
+++ b/examples/webenginewidgets/contentmanipulation/main.cpp
@@ -54,6 +54,7 @@
int main(int argc, char * argv[])
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QUrl url;
diff --git a/examples/webenginewidgets/cookiebrowser/main.cpp b/examples/webenginewidgets/cookiebrowser/main.cpp
index c122eb7c3..15a87609b 100644
--- a/examples/webenginewidgets/cookiebrowser/main.cpp
+++ b/examples/webenginewidgets/cookiebrowser/main.cpp
@@ -45,6 +45,7 @@
int main(int argc, char *argv[])
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
MainWindow window(QUrl("http://qt.io"));
window.show();
diff --git a/examples/webenginewidgets/demobrowser/history.cpp b/examples/webenginewidgets/demobrowser/history.cpp
index 188490aca..bce65b917 100644
--- a/examples/webenginewidgets/demobrowser/history.cpp
+++ b/examples/webenginewidgets/demobrowser/history.cpp
@@ -137,7 +137,7 @@ void HistoryManager::setHistory(const QList<HistoryItem> &history, bool loadedAn
if (!loadedAndSorted)
qSort(m_history.begin(), m_history.end());
- checkForExpired();
+ checkForExpired(loadedAndSorted);
if (loadedAndSorted) {
m_lastSavedUrl = m_history.value(0).url;
@@ -163,7 +163,7 @@ HistoryTreeModel *HistoryManager::historyTreeModel() const
return m_historyTreeModel;
}
-void HistoryManager::checkForExpired()
+void HistoryManager::checkForExpired(bool removeEntriesDirectly)
{
if (m_historyLimit < 0 || m_history.isEmpty())
return;
@@ -185,7 +185,11 @@ void HistoryManager::checkForExpired()
const HistoryItem& item = m_history.last();
// remove from saved file also
m_lastSavedUrl = QString();
- emit entryRemoved(item);
+
+ if (removeEntriesDirectly)
+ m_history.takeLast();
+ else
+ emit entryRemoved(item);
}
if (nextTimeout > 0)
diff --git a/examples/webenginewidgets/demobrowser/history.h b/examples/webenginewidgets/demobrowser/history.h
index 6d7da5e6d..2a6dce9e1 100644
--- a/examples/webenginewidgets/demobrowser/history.h
+++ b/examples/webenginewidgets/demobrowser/history.h
@@ -126,7 +126,7 @@ public slots:
private slots:
void save();
- void checkForExpired();
+ void checkForExpired(bool removeExpiredEntriesDirectly = false);
protected:
void addHistoryItem(const HistoryItem &item);
diff --git a/examples/webenginewidgets/demobrowser/main.cpp b/examples/webenginewidgets/demobrowser/main.cpp
index 4427a446d..41cae306a 100644
--- a/examples/webenginewidgets/demobrowser/main.cpp
+++ b/examples/webenginewidgets/demobrowser/main.cpp
@@ -54,6 +54,7 @@
int main(int argc, char **argv)
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
Q_INIT_RESOURCE(data);
BrowserApplication application(argc, argv);
if (!application.isTheOnlyBrowser())
diff --git a/examples/webenginewidgets/markdowneditor/main.cpp b/examples/webenginewidgets/markdowneditor/main.cpp
index 5d1e56eed..1051dcfd4 100644
--- a/examples/webenginewidgets/markdowneditor/main.cpp
+++ b/examples/webenginewidgets/markdowneditor/main.cpp
@@ -56,6 +56,7 @@
int main(int argc, char *argv[])
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication a(argc, argv);
MainWindow window;
diff --git a/examples/webenginewidgets/minimal/doc/src/minimal.qdoc b/examples/webenginewidgets/minimal/doc/src/minimal.qdoc
index 22f28e604..dd6a70566 100644
--- a/examples/webenginewidgets/minimal/doc/src/minimal.qdoc
+++ b/examples/webenginewidgets/minimal/doc/src/minimal.qdoc
@@ -42,7 +42,10 @@
\section1 The Code
- In \c main.cpp we instantiate a QApplication and a QWebEngineView. The URL
+ In the \c main function we first set the Qt::AA_EnableHighDpiScaling.
+ This lets the web view automatically scale on high-dpi displays.
+
+ Next, we instantiate a QApplication and a QWebEngineView. The URL
to load is set by calling \l QWebEngineView::setUrl. The view widget is
given a reasonable default size, and shown.
Finally, QApplication::exec() launches the main event loop.
diff --git a/examples/webenginewidgets/minimal/main.cpp b/examples/webenginewidgets/minimal/main.cpp
index d9a137739..729d68fa0 100644
--- a/examples/webenginewidgets/minimal/main.cpp
+++ b/examples/webenginewidgets/minimal/main.cpp
@@ -43,6 +43,7 @@
int main(int argc, char *argv[])
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
QWebEngineView view;
diff --git a/examples/webenginewidgets/simplebrowser/main.cpp b/examples/webenginewidgets/simplebrowser/main.cpp
index 1d2796b8c..fa9f44c34 100644
--- a/examples/webenginewidgets/simplebrowser/main.cpp
+++ b/examples/webenginewidgets/simplebrowser/main.cpp
@@ -57,6 +57,8 @@ QString getCommandLineUrlArgument()
int main(int argc, char **argv)
{
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+
QApplication app(argc, argv);
app.setWindowIcon(QIcon(QLatin1String(":simplebrowser.svg")));
diff --git a/src/core/gyp_run.pro b/src/core/gyp_run.pro
index a1b33e258..8c4aeb163 100644
--- a/src/core/gyp_run.pro
+++ b/src/core/gyp_run.pro
@@ -89,9 +89,16 @@ contains(QT_ARCH, "arm") {
contains(QT_ARCH, "mips") {
GYP_CONFIG += target_arch=mipsel
- contains(QMAKE_CFLAGS, "mips32r6"): mips_arch_variant=\"r6\"
- else: contains(QMAKE_CFLAGS, "mips32r2"): mips_arch_variant=\"r2\"
- else: contains(QMAKE_CFLAGS, "mips32"): mips_arch_variant=\"r1\"
+ MARCH = $$extractCFlag("-march=.*")
+ !isEmpty(MARCH) {
+ equals(MARCH, "mips32r6"): GYP_CONFIG += mips_arch_variant=\"r6\"
+ else: equals(MARCH, "mips32r2"): GYP_CONFIG += mips_arch_variant=\"r2\"
+ else: equals(MARCH, "mips32"): GYP_CONFIG += mips_arch_variant=\"r1\"
+ } else {
+ contains(QMAKE_CFLAGS, "mips32r6"): GYP_CONFIG += mips_arch_variant=\"r6\"
+ else: contains(QMAKE_CFLAGS, "mips32r2"): GYP_CONFIG += mips_arch_variant=\"r2\"
+ else: contains(QMAKE_CFLAGS, "mips32"): GYP_CONFIG += mips_arch_variant=\"r1\"
+ }
contains(QMAKE_CFLAGS, "-mdsp2"): GYP_CONFIG += mips_dsp_rev=2
else: contains(QMAKE_CFLAGS, "-mdsp"): GYP_CONFIG += mips_dsp_rev=1
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 99e4da27e..f45db6bf4 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -239,6 +239,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget
, m_didFirstVisuallyNonEmptyLayout(false)
, m_adapterClient(0)
, m_imeInProgress(false)
+ , m_receivedEmptyImeText(false)
, m_anchorPositionWithinSelection(0)
, m_cursorPositionWithinSelection(0)
, m_initPending(false)
@@ -949,6 +950,19 @@ void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event)
QCursor::setPos(m_lockedMousePosition);
}
+ if (m_imeInProgress && event->type() == QMouseEvent::MouseButtonPress) {
+ m_imeInProgress = false;
+ // Tell input method to commit the pre-edit string entered so far, and finish the
+ // composition operation.
+#ifdef Q_OS_WIN
+ // Yes the function name is counter-intuitive, but commit isn't actually implemented
+ // by the Windows QPA, and reset does exactly what is necessary in this case.
+ qApp->inputMethod()->reset();
+#else
+ qApp->inputMethod()->commit();
+#endif
+ }
+
m_host->ForwardMouseEvent(webEvent);
}
@@ -957,15 +971,16 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev)
if (IsMouseLocked() && ev->key() == Qt::Key_Escape && ev->type() == QEvent::KeyRelease)
UnlockMouse();
- if (m_imeInProgress) {
+ if (m_receivedEmptyImeText) {
// IME composition was not finished with a valid commit string.
// We're getting the composition result in a key event.
if (ev->key() != 0) {
// The key event is not a result of an IME composition. Cancel IME.
m_host->ImeCancelComposition();
- m_imeInProgress = false;
+ m_receivedEmptyImeText = false;
} else {
if (ev->type() == QEvent::KeyRelease) {
+ m_receivedEmptyImeText = false;
m_host->ImeConfirmComposition(toString16(ev->text()), gfx::Range::InvalidRange(),
false);
m_imeInProgress = false;
@@ -1005,6 +1020,25 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev)
const QList<QInputMethodEvent::Attribute> &attributes = ev->attributes();
std::vector<blink::WebCompositionUnderline> underlines;
+ auto ensureValidSelectionRange = [&]() {
+ if (!selectionRange.IsValid()) {
+ // We did not receive a valid selection range, hence the range is going to mark the
+ // cursor position.
+ int newCursorPosition =
+ (cursorPositionInPreeditString < 0) ? preeditString.length()
+ : cursorPositionInPreeditString;
+ selectionRange.set_start(newCursorPosition);
+ selectionRange.set_end(newCursorPosition);
+ }
+ };
+
+ auto setCompositionForPreEditString = [&](){
+ ensureValidSelectionRange();
+ m_host->ImeSetComposition(toString16(preeditString),
+ underlines,
+ selectionRange.start(),
+ selectionRange.end());
+ };
Q_FOREACH (const QInputMethodEvent::Attribute &attribute, attributes) {
switch (attribute.type) {
@@ -1018,8 +1052,11 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev)
break;
}
case QInputMethodEvent::Cursor:
- if (attribute.length)
- cursorPositionInPreeditString = attribute.start;
+ // Always set the position of the cursor, even if it's marked invisible by Qt, otherwise
+ // there is no way the user will know which part of the composition string will be
+ // changed, when performing an IME-specific action (like selecting a different word
+ // suggestion).
+ cursorPositionInPreeditString = attribute.start;
break;
case QInputMethodEvent::Selection:
selectionRange.set_start(qMin(attribute.start, (attribute.start + attribute.length)));
@@ -1034,16 +1071,42 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev)
gfx::Range replacementRange = (replacementLength > 0) ? gfx::Range(replacementStart, replacementStart + replacementLength)
: gfx::Range::InvalidRange();
m_host->ImeConfirmComposition(toString16(commitString), replacementRange, false);
- m_imeInProgress = false;
- } else if (!preeditString.isEmpty()) {
- if (!selectionRange.IsValid()) {
- // We did not receive a valid selection range, hence the range is going to mark the cursor position.
- int newCursorPosition = (cursorPositionInPreeditString < 0) ? preeditString.length() : cursorPositionInPreeditString;
- selectionRange.set_start(newCursorPosition);
- selectionRange.set_end(newCursorPosition);
+
+ // We might get a commit string and a pre-edit string in a single event, which means
+ // we need to confirm the怀last composition, and start a new composition.
+ if (!preeditString.isEmpty()) {
+ setCompositionForPreEditString();
+ m_imeInProgress = true;
+ } else {
+ m_imeInProgress = false;
}
- m_host->ImeSetComposition(toString16(preeditString), underlines, selectionRange.start(), selectionRange.end());
+ m_receivedEmptyImeText = false;
+
+ } else if (!preeditString.isEmpty()) {
+ setCompositionForPreEditString();
m_imeInProgress = true;
+ m_receivedEmptyImeText = false;
+ } else {
+ // There are so-far two known cases, when an empty QInputMethodEvent is received.
+ // First one happens when backspace is used to remove the last character in the pre-edit
+ // string, thus signaling the end of the composition.
+ // The second one happens (on Windows) when a Korean char gets composed, but instead of
+ // the event having a commit string, both strings are empty, and the actual char is received
+ // as a QKeyEvent after the QInputMethodEvent is processed.
+ // In lieu of the second case, we can't simply cancel the composition on an empty event,
+ // and then add the Korean char when QKeyEvent is received, because that leads to text
+ // flickering in the textarea (or any other element).
+ // Instead we postpone the processing of the empty QInputMethodEvent by posting it
+ // to the same focused object, and cancelling the composition on the next event loop tick.
+ if (!m_receivedEmptyImeText && m_imeInProgress) {
+ m_receivedEmptyImeText = true;
+ m_imeInProgress = false;
+ QInputMethodEvent *eventCopy = new QInputMethodEvent(*ev);
+ QGuiApplication::postEvent(qApp->focusObject(), eventCopy);
+ } else {
+ m_receivedEmptyImeText = false;
+ m_host->ImeCancelComposition();
+ }
}
}
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index 67e7461b3..523d1c49d 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -241,6 +241,7 @@ private:
ui::TextInputType m_currentInputType;
bool m_imeInProgress;
+ bool m_receivedEmptyImeText;
QRect m_cursorRect;
size_t m_anchorPositionWithinSelection;
size_t m_cursorPositionWithinSelection;
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index 505a684eb..10809a764 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -659,14 +659,11 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev, doub
webEvent.modifiers = modifiersForEvent(ev);
webEvent.timeStampSeconds = currentTimeForEvent(ev);
- if (ev->orientation() == Qt::Horizontal)
- webEvent.wheelTicksX = ev->delta() / 120.0f;
- else
- webEvent.wheelTicksY = ev->delta() / 120.0f;
+ webEvent.wheelTicksX = ev->angleDelta().x() / QWheelEvent::DefaultDeltasPerStep;
+ webEvent.wheelTicksY = ev->angleDelta().y() / QWheelEvent::DefaultDeltasPerStep;
-
- // Since we report the scroll by the pixel, convert the delta to pixel distance using standard scroll step.
- // Use the same single scroll step as QTextEdit (in QTextEditPrivate::init [h,v]bar->setSingleStep)
+ // We can't use the device specific QWheelEvent::pixelDelta(), so we calculate
+ // a pixel delta based on ticks and scroll per line.
static const float cDefaultQtScrollStep = 20.f;
webEvent.deltaX = webEvent.wheelTicksX * wheelScrollLines * cDefaultQtScrollStep;
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index ac25cd4d2..ced8c1452 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -93,6 +93,27 @@
QT_BEGIN_NAMESPACE
using namespace QtWebEngineCore;
+QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event)
+{
+ static struct {
+ QKeySequence::StandardKey standardKey;
+ QQuickWebEngineView::WebAction action;
+ } editorActions[] = {
+ { QKeySequence::Cut, QQuickWebEngineView::Cut },
+ { QKeySequence::Copy, QQuickWebEngineView::Copy },
+ { QKeySequence::Paste, QQuickWebEngineView::Paste },
+ { QKeySequence::Undo, QQuickWebEngineView::Undo },
+ { QKeySequence::Redo, QQuickWebEngineView::Redo },
+ { QKeySequence::SelectAll, QQuickWebEngineView::SelectAll },
+ { QKeySequence::UnknownKey, QQuickWebEngineView::NoWebAction }
+ };
+ for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
+ if (event == editorActions[i].standardKey)
+ return editorActions[i].action;
+
+ return QQuickWebEngineView::NoWebAction;
+}
+
#ifndef QT_NO_ACCESSIBILITY
static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *object)
{
@@ -343,7 +364,8 @@ void QQuickWebEngineViewPrivate::allowCertificateError(const QSharedPointer<Cert
Q_Q(QQuickWebEngineView);
QQuickWebEngineCertificateError *quickController = new QQuickWebEngineCertificateError(errorController);
- QQmlEngine::setObjectOwnership(quickController, QQmlEngine::JavaScriptOwnership);
+ // mark the object for gc by creating temporary jsvalue
+ qmlEngine(q)->newQObject(quickController);
Q_EMIT q->certificateError(quickController);
if (!quickController->deferred() && !quickController->answered())
quickController->rejectCertificate();
@@ -526,6 +548,18 @@ void QQuickWebEngineViewPrivate::focusContainer()
void QQuickWebEngineViewPrivate::unhandledKeyEvent(QKeyEvent *event)
{
Q_Q(QQuickWebEngineView);
+#ifdef Q_OS_OSX
+ if (event->type() == QEvent::KeyPress) {
+ QQuickWebEngineView::WebAction action = editorActionForKeyEvent(event);
+ if (action != QQuickWebEngineView::NoWebAction) {
+ // Try triggering a registered short-cut
+ if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event))
+ return;
+ q->triggerWebAction(action);
+ return;
+ }
+ }
+#endif
if (q->parentItem())
q->window()->sendEvent(q->parentItem(), event);
}
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 1b5198110..f13bfd09a 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -73,6 +73,8 @@ class QQmlContext;
class QQuickWebEngineSettings;
class QQuickWebEngineFaviconProvider;
+QQuickWebEngineView::WebAction editorActionForKeyEvent(QKeyEvent* event);
+
#ifdef ENABLE_QML_TESTSUPPORT_API
class QQuickWebEngineTestSupport;
#endif
diff --git a/src/webengine/doc/src/qtwebengine-index.qdoc b/src/webengine/doc/src/qtwebengine-index.qdoc
index e7314fcf9..fd7fe2351 100644
--- a/src/webengine/doc/src/qtwebengine-index.qdoc
+++ b/src/webengine/doc/src/qtwebengine-index.qdoc
@@ -38,10 +38,6 @@
\annotatedlist qtwebengine-modules
- For Qt Quick applications, Qt WebEngine provides the following QML modules:
-
- \annotatedlist qtwebengine-qmlmodules
-
\section1 Articles and Guides
\list
diff --git a/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc b/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc
index 954562e38..87022262d 100644
--- a/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc
+++ b/src/webengine/doc/src/qtwebengine-qmlmodule.qdoc
@@ -27,7 +27,7 @@
\qmlmodule QtWebEngine 1.3
\title Qt WebEngine QML Types
\brief Provides QML types for rendering web content within a QML application
- \ingroup qtwebengine-qmlmodules
+ \ingroup qtwebengine-modules
The QML types can be imported into your application using the following import statements in
your .qml file:
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
index 5e39cc2b3..d0bd67e6a 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp
@@ -210,6 +210,18 @@ void RenderWidgetHostViewQtDelegateQuick::inputMethodStateChanged(bool editorVis
}
+bool RenderWidgetHostViewQtDelegateQuick::event(QEvent *event)
+{
+ if (event->type() == QEvent::ShortcutOverride) {
+ if (editorActionForKeyEvent(static_cast<QKeyEvent*>(event)) != QQuickWebEngineView::NoWebAction) {
+ event->accept();
+ return true;
+ }
+ }
+
+ return QQuickItem::event(event);
+}
+
void RenderWidgetHostViewQtDelegateQuick::focusInEvent(QFocusEvent *event)
{
m_client->forwardEvent(event);
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h
index 66bc63732..c51ca3408 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quick.h
+++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h
@@ -77,6 +77,7 @@ public:
virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { }
protected:
+ virtual bool event(QEvent *event) Q_DECL_OVERRIDE;
virtual void focusInEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
virtual void focusOutEvent(QFocusEvent *event) Q_DECL_OVERRIDE;
virtual void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index bb0db402b..db1915b9f 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -83,6 +83,8 @@
#include <QStyle>
#include <QUrl>
+#include <private/qguiapplication_p.h>
+
QT_BEGIN_NAMESPACE
using namespace QtWebEngineCore;
@@ -103,6 +105,27 @@ static QWebEnginePage::WebWindowType toWindowType(WebContentsAdapterClient::Wind
}
}
+QWebEnginePage::WebAction editorActionForKeyEvent(QKeyEvent* event)
+{
+ static struct {
+ QKeySequence::StandardKey standardKey;
+ QWebEnginePage::WebAction action;
+ } editorActions[] = {
+ { QKeySequence::Cut, QWebEnginePage::Cut },
+ { QKeySequence::Copy, QWebEnginePage::Copy },
+ { QKeySequence::Paste, QWebEnginePage::Paste },
+ { QKeySequence::Undo, QWebEnginePage::Undo },
+ { QKeySequence::Redo, QWebEnginePage::Redo },
+ { QKeySequence::SelectAll, QWebEnginePage::SelectAll },
+ { QKeySequence::UnknownKey, QWebEnginePage::NoWebAction }
+ };
+ for (int i = 0; editorActions[i].standardKey != QKeySequence::UnknownKey; ++i)
+ if (event == editorActions[i].standardKey)
+ return editorActions[i].action;
+
+ return QWebEnginePage::NoWebAction;
+}
+
QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile)
: adapter(new WebContentsAdapter)
, history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this)))
@@ -244,6 +267,19 @@ void QWebEnginePagePrivate::focusContainer()
void QWebEnginePagePrivate::unhandledKeyEvent(QKeyEvent *event)
{
+#ifdef Q_OS_OSX
+ Q_Q(QWebEnginePage);
+ if (event->type() == QEvent::KeyPress) {
+ QWebEnginePage::WebAction action = editorActionForKeyEvent(event);
+ if (action != QWebEnginePage::NoWebAction) {
+ // Try triggering a registered short-cut
+ if (QGuiApplicationPrivate::instance()->shortcutMap.tryShortcut(event))
+ return;
+ q->triggerAction(action);
+ return;
+ }
+ }
+#endif
if (view && view->parentWidget())
QGuiApplication::sendEvent(view->parentWidget(), event);
}
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index c0b1b9a4e..fb0b85268 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -71,6 +71,8 @@ class QWebEngineProfile;
class QWebEngineSettings;
class QWebEngineView;
+QWebEnginePage::WebAction editorActionForKeyEvent(QKeyEvent* event);
+
class QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient
{
public:
diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
index 99621b602..f0385a252 100644
--- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
+++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp
@@ -326,6 +326,13 @@ bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event)
}
}
+ if (event->type() == QEvent::ShortcutOverride) {
+ if (editorActionForKeyEvent(static_cast<QKeyEvent*>(event)) != QWebEnginePage::NoWebAction) {
+ event->accept();
+ return true;
+ }
+ }
+
if (event->type() == QEvent::MouseButtonDblClick) {
// QWidget keeps the Qt4 behavior where the DblClick event would replace the Press event.
// QtQuick is different by sending both the Press and DblClick events for the second press
diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
index 1c5461fa7..078e70255 100644
--- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
+++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
@@ -547,9 +547,10 @@ void tst_QQuickWebEngineView::stopSettingFocusWhenDisabled_data()
}
class MouseTouchEventRecordingItem : public QQuickItem {
+ Q_OBJECT
public:
- explicit MouseTouchEventRecordingItem(QQuickItem *parent = 0) :
- QQuickItem(parent), m_eventCounter(0) {
+ explicit MouseTouchEventRecordingItem(QQuickItem* child, QQuickItem *parent = 0) :
+ QQuickItem(parent), m_eventCounter(0), m_child(child) {
setFlag(ItemHasContents);
setAcceptedMouseButtons(Qt::AllButtons);
setAcceptHoverEvents(true);
@@ -569,9 +570,6 @@ public:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
case QEvent::TouchCancel:
- case QEvent::HoverEnter:
- case QEvent::HoverMove:
- case QEvent::HoverLeave:
++m_eventCounter;
event->accept();
return true;
@@ -591,16 +589,34 @@ public:
return m_eventCounter;
}
+public Q_SLOTS:
+ void changeWidth() {
+ if (m_child)
+ setWidth(m_child->width());
+ }
+
+ void changeHeight() {
+ if (m_child)
+ setHeight(m_child->height());
+ }
+
private:
int m_eventCounter;
+ QQuickItem *m_child;
};
void tst_QQuickWebEngineView::inputEventForwardingDisabledWhenActiveFocusOnPressDisabled()
{
QQuickWebEngineView *view = webEngineView();
- MouseTouchEventRecordingItem item;
+ MouseTouchEventRecordingItem item(view);
item.setParentItem(m_window->contentItem());
- item.setSize(QSizeF(640, 480));
+
+ // Resize the event recorder whenever the view is resized, so that all event positions
+ // are contained in both of the item regions.
+ QObject::connect(view, &QQuickItem::widthChanged, &item,
+ &MouseTouchEventRecordingItem::changeWidth);
+ QObject::connect(view, &QQuickItem::heightChanged, &item,
+ &MouseTouchEventRecordingItem::changeHeight);
view->setParentItem(&item);
view->setSize(QSizeF(640, 480));
m_window->show();
@@ -608,6 +624,7 @@ void tst_QQuickWebEngineView::inputEventForwardingDisabledWhenActiveFocusOnPress
// Simulate click and move of mouse, so that last known position in the application
// is updated, thus a mouse move event is not generated when we don't expect it.
QTest::mouseClick(view->window(), Qt::LeftButton);
+ QTRY_COMPARE(item.eventCount(), 2);
item.clearEventCount();
// First disable view, so it does not receive focus on page load.