aboutsummaryrefslogtreecommitdiffstats
path: root/src/quickwidgets/qquickwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickwidgets/qquickwidget.cpp')
-rw-r--r--src/quickwidgets/qquickwidget.cpp180
1 files changed, 130 insertions, 50 deletions
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index 2e8623f508..a098c94670 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -80,7 +80,7 @@ class QQuickWidgetRenderControl : public QQuickRenderControl
{
public:
QQuickWidgetRenderControl(QQuickWidget *quickwidget) : m_quickWidget(quickwidget) {}
- QWindow *renderWindow(QPoint *offset) Q_DECL_OVERRIDE {
+ QWindow *renderWindow(QPoint *offset) override {
if (offset)
*offset = m_quickWidget->mapTo(m_quickWidget->window(), QPoint());
return m_quickWidget->window()->windowHandle();
@@ -184,15 +184,15 @@ void QQuickWidgetPrivate::handleWindowChange()
}
QQuickWidgetPrivate::QQuickWidgetPrivate()
- : root(0)
- , component(0)
- , offscreenWindow(0)
- , offscreenSurface(0)
- , renderControl(0)
+ : root(nullptr)
+ , component(nullptr)
+ , offscreenWindow(nullptr)
+ , offscreenSurface(nullptr)
+ , renderControl(nullptr)
#if QT_CONFIG(opengl)
- , fbo(0)
- , resolvedFbo(0)
- , context(0)
+ , fbo(nullptr)
+ , resolvedFbo(nullptr)
+ , context(nullptr)
#endif
, resizeMode(QQuickWidget::SizeViewToRootObject)
, initialSize(0,0)
@@ -201,6 +201,7 @@ QQuickWidgetPrivate::QQuickWidgetPrivate()
, fakeHidden(false)
, requestedSamples(0)
, useSoftwareRenderer(false)
+ , forceFullUpdate(false)
{
}
@@ -232,11 +233,11 @@ void QQuickWidgetPrivate::execute()
if (root) {
delete root;
- root = 0;
+ root = nullptr;
}
if (component) {
delete component;
- component = 0;
+ component = nullptr;
}
if (!source.isEmpty()) {
QML_MEMORY_SCOPE_URL(engine.data()->baseUrl().resolved(source));
@@ -306,6 +307,10 @@ void QQuickWidgetPrivate::render(bool needsSync)
auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
if (softwareRenderer && !softwareImage.isNull()) {
softwareRenderer->setCurrentPaintDevice(&softwareImage);
+ if (forceFullUpdate) {
+ softwareRenderer->markDirty();
+ forceFullUpdate = false;
+ }
renderControl->render();
updateRegion += softwareRenderer->flushRegion();
@@ -367,7 +372,7 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
\module QtQuickWidgets
\title Qt Quick Widgets C++ Classes
\ingroup modules
- \brief The C++ API provided by the Qt Quick Widgets module
+ \brief The C++ API provided by the Qt Quick Widgets module.
\qtvariable quickwidgets
To link against the module, add this line to your \l qmake
@@ -423,7 +428,7 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
entire purpose of QQuickWidget is to render Quick scenes without a separate native
window, hence making it a native widget should always be avoided.
- \section1 Scene graph and context persistency
+ \section1 Scene Graph and Context Persistency
QQuickWidget honors QQuickWindow::isPersistentSceneGraph(), meaning that
applications can decide - by calling
@@ -480,11 +485,18 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
compatible however and attempting to construct a QQuickWidget will lead to
problems.
+ \section1 Tab Key Handling
+
+ On press of the \c[TAB] key, the item inside the QQuickWidget gets focus. If
+ this item can handle \c[TAB] key press, focus will change accordingly within
+ the item, otherwise the next widget in the focus chain gets focus.
+
\sa {Exposing Attributes of C++ Types to QML}, {Qt Quick Widgets Example}, QQuickView
*/
-/*! \fn void QQuickWidget::statusChanged(QQuickWidget::Status status)
+/*!
+ \fn void QQuickWidget::statusChanged(QQuickWidget::Status status)
This signal is emitted when the component's current \a status changes.
*/
@@ -494,7 +506,7 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
*/
QQuickWidget::QQuickWidget(QWidget *parent)
-: QWidget(*(new QQuickWidgetPrivate), parent, 0)
+: QWidget(*(new QQuickWidgetPrivate), parent, nullptr)
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
@@ -522,7 +534,7 @@ QQuickWidget::QQuickWidget(const QUrl &source, QWidget *parent)
\sa Status, status(), errors()
*/
QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
- : QWidget(*(new QQuickWidgetPrivate), parent, 0)
+ : QWidget(*(new QQuickWidgetPrivate), parent, nullptr)
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
@@ -538,7 +550,7 @@ QQuickWidget::~QQuickWidget()
// be a child of the QQuickWidgetPrivate, and will be destroyed by its dtor
Q_D(QQuickWidget);
delete d->root;
- d->root = 0;
+ d->root = nullptr;
}
/*!
@@ -582,7 +594,7 @@ void QQuickWidget::setContent(const QUrl& url, QQmlComponent *component, QObject
if (d->component && d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
for (const QQmlError &error : errorList) {
- QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), nullptr).warning()
<< error;
}
emit statusChanged(status());
@@ -768,6 +780,7 @@ void QQuickWidgetPrivate::updateSize()
QSize newSize = QSize(root->width(), root->height());
if (newSize.isValid() && newSize != q->size()) {
q->resize(newSize);
+ q->updateGeometry();
}
} else if (resizeMode == QQuickWidget::SizeRootObjectToView) {
bool needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
@@ -790,7 +803,7 @@ void QQuickWidgetPrivate::updateSize()
void QQuickWidgetPrivate::updatePosition()
{
Q_Q(QQuickWidget);
- if (offscreenWindow == 0)
+ if (offscreenWindow == nullptr)
return;
const QPoint &pos = q->mapToGlobal(QPoint(0, 0));
@@ -864,7 +877,7 @@ void QQuickWidgetPrivate::createContext()
if (!context->create()) {
const bool isEs = context->isOpenGLES();
delete context;
- context = 0;
+ context = nullptr;
handleContextCreationFailure(offscreenWindow->requestedFormat(), isEs);
return;
}
@@ -890,10 +903,10 @@ void QQuickWidgetPrivate::createContext()
void QQuickWidgetPrivate::destroyContext()
{
delete offscreenSurface;
- offscreenSurface = 0;
+ offscreenSurface = nullptr;
#if QT_CONFIG(opengl)
delete context;
- context = 0;
+ context = nullptr;
#endif
}
@@ -913,9 +926,10 @@ void QQuickWidget::createFramebufferObject()
d->offscreenWindow->setGeometry(globalPos.x(), globalPos.y(), width(), height());
if (d->useSoftwareRenderer) {
- const QSize imageSize = size() * devicePixelRatio();
+ const QSize imageSize = size() * devicePixelRatioF();
d->softwareImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
- d->softwareImage.setDevicePixelRatio(devicePixelRatio());
+ d->softwareImage.setDevicePixelRatio(devicePixelRatioF());
+ d->forceFullUpdate = true;
return;
}
@@ -928,7 +942,7 @@ void QQuickWidget::createFramebufferObject()
}
QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext();
- if (shareWindowContext && context->shareContext() != shareWindowContext) {
+ if (shareWindowContext && context->shareContext() != shareWindowContext && !qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts)) {
context->setShareContext(shareWindowContext);
context->setScreen(shareWindowContext->screen());
if (!context->create())
@@ -960,7 +974,7 @@ void QQuickWidget::createFramebufferObject()
format.setInternalTextureFormat(GL_SRGB8_ALPHA8_EXT);
#endif
- const QSize fboSize = size() * devicePixelRatio();
+ const QSize fboSize = size() * devicePixelRatioF();
// Could be a simple hide - show, in which case the previous fbo is just fine.
if (!d->fbo || d->fbo->size() != fboSize) {
@@ -1002,9 +1016,9 @@ void QQuickWidget::destroyFramebufferObject()
#if QT_CONFIG(opengl)
delete d->fbo;
- d->fbo = 0;
+ d->fbo = nullptr;
delete d->resolvedFbo;
- d->resolvedFbo = 0;
+ d->resolvedFbo = nullptr;
#endif
}
@@ -1025,7 +1039,7 @@ void QQuickWidget::continueExecute()
if (d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
for (const QQmlError &error : errorList) {
- QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), nullptr).warning()
<< error;
}
emit statusChanged(status());
@@ -1037,7 +1051,7 @@ void QQuickWidget::continueExecute()
if (d->component->isError()) {
const QList<QQmlError> errorList = d->component->errors();
for (const QQmlError &error : errorList) {
- QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning()
+ QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), nullptr).warning()
<< error;
}
emit statusChanged(status());
@@ -1070,7 +1084,7 @@ void QQuickWidgetPrivate::setRootObject(QObject *obj)
<< "Ensure your QML code is written for QtQuick 2, and uses a root that is or" << endl
<< "inherits from QtQuick's Item (not a Timer, QtObject, etc)." << endl;
delete obj;
- root = 0;
+ root = nullptr;
}
if (root) {
initialSize = rootObjectSize();
@@ -1181,7 +1195,7 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
// Software Renderer
if (d->useSoftwareRenderer) {
needsSync = true;
- if (d->softwareImage.size() != size() * devicePixelRatio()) {
+ if (d->softwareImage.size() != size() * devicePixelRatioF()) {
createFramebufferObject();
}
} else {
@@ -1191,7 +1205,7 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
// during hide - resize - show sequences and also during application exit.
if (!d->fbo && !d->offscreenWindow->openglContext())
return;
- if (!d->fbo || d->fbo->size() != size() * devicePixelRatio()) {
+ if (!d->fbo || d->fbo->size() != size() * devicePixelRatioF()) {
needsSync = true;
createFramebufferObject();
}
@@ -1214,6 +1228,22 @@ void QQuickWidget::resizeEvent(QResizeEvent *e)
}
/*! \reimp */
+bool QQuickWidget::focusNextPrevChild(bool next)
+{
+ Q_D(QQuickWidget);
+ QKeyEvent event(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, event.key(),
+ Qt::NoModifier);
+ QCoreApplication::sendEvent(d->offscreenWindow, &event);
+
+ QKeyEvent releaseEvent(QEvent::KeyRelease, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
+ Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, releaseEvent.key(),
+ Qt::NoModifier);
+ QCoreApplication::sendEvent(d->offscreenWindow, &releaseEvent);
+ return event.isAccepted();
+}
+
+/*! \reimp */
void QQuickWidget::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWidget);
@@ -1240,11 +1270,12 @@ void QQuickWidget::mouseMoveEvent(QMouseEvent *e)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove, e->localPos().x(),
e->localPos().y());
- // Use the constructor taking localPos and screenPos. That puts localPos into the
- // event's localPos and windowPos, and screenPos into the event's screenPos. This way
- // the windowPos in e is ignored and is replaced by localPos. This is necessary
- // because QQuickWindow thinks of itself as a top-level window always.
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
+ // Put localPos into the event's localPos and windowPos, and screenPos into the
+ // event's screenPos. This way the windowPos in e is ignored and is replaced by
+ // localPos. This is necessary because QQuickWindow thinks of itself as a
+ // top-level window always.
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
+ e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
e->setAccepted(mappedEvent.isAccepted());
}
@@ -1258,12 +1289,12 @@ void QQuickWidget::mouseDoubleClickEvent(QMouseEvent *e)
// As the second mouse press is suppressed in widget windows we emulate it here for QML.
// See QTBUG-25831
- QMouseEvent pressEvent(QEvent::MouseButtonPress, e->localPos(), e->screenPos(), e->button(),
- e->buttons(), e->modifiers());
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, e->localPos(), e->localPos(), e->screenPos(),
+ e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &pressEvent);
e->setAccepted(pressEvent.isAccepted());
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(),
- e->modifiers());
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
+ e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
}
@@ -1323,7 +1354,8 @@ void QQuickWidget::mousePressEvent(QMouseEvent *e)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, e->button(),
e->buttons());
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
+ e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
e->setAccepted(mappedEvent.isAccepted());
}
@@ -1335,7 +1367,8 @@ void QQuickWidget::mouseReleaseEvent(QMouseEvent *e)
Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, e->button(),
e->buttons());
- QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers());
+ QMouseEvent mappedEvent(e->type(), e->localPos(), e->localPos(), e->screenPos(),
+ e->button(), e->buttons(), e->modifiers(), e->source());
QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
e->setAccepted(mappedEvent.isAccepted());
}
@@ -1385,15 +1418,36 @@ static Qt::WindowState resolveWindowState(Qt::WindowStates states)
return Qt::WindowNoState;
}
+static void remapInputMethodQueryEvent(QObject *object, QInputMethodQueryEvent *e)
+{
+ auto item = qobject_cast<QQuickItem *>(object);
+ if (!item)
+ return;
+
+ // Remap all QRectF values.
+ for (auto query : {Qt::ImCursorRectangle, Qt::ImAnchorRectangle, Qt::ImInputItemClipRectangle}) {
+ if (e->queries() & query) {
+ auto value = e->value(query);
+ if (value.canConvert<QRectF>())
+ e->setValue(query, item->mapRectToScene(value.toRectF()));
+ }
+ }
+ // Remap all QPointF values.
+ if (e->queries() & Qt::ImCursorPosition) {
+ auto value = e->value(Qt::ImCursorPosition);
+ if (value.canConvert<QPointF>())
+ e->setValue(Qt::ImCursorPosition, item->mapToScene(value.toPointF()));
+ }
+}
+
/*! \reimp */
bool QQuickWidget::event(QEvent *e)
{
Q_D(QQuickWidget);
switch (e->type()) {
- case QEvent::InputMethod:
- case QEvent::InputMethodQuery:
+ case QEvent::Leave:
case QEvent::TouchBegin:
case QEvent::TouchEnd:
case QEvent::TouchUpdate:
@@ -1401,6 +1455,19 @@ bool QQuickWidget::event(QEvent *e)
// Touch events only have local and global positions, no need to map.
return QCoreApplication::sendEvent(d->offscreenWindow, e);
+ case QEvent::InputMethod:
+ return QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
+ case QEvent::InputMethodQuery:
+ {
+ bool eventResult = QCoreApplication::sendEvent(d->offscreenWindow->focusObject(), e);
+ // The result in focusObject are based on offscreenWindow. But
+ // the inputMethodTransform won't get updated because the focus
+ // is on QQuickWidget. We need to remap the value based on the
+ // widget.
+ remapInputMethodQueryEvent(d->offscreenWindow->focusObject(), static_cast<QInputMethodQueryEvent *>(e));
+ return eventResult;
+ }
+
case QEvent::WindowChangeInternal:
d->handleWindowChange();
break;
@@ -1443,6 +1510,14 @@ bool QQuickWidget::event(QEvent *e)
case QEvent::ShortcutOverride:
return QCoreApplication::sendEvent(d->offscreenWindow, e);
+ case QEvent::Enter: {
+ QEnterEvent *enterEvent = static_cast<QEnterEvent *>(e);
+ QEnterEvent mappedEvent(enterEvent->localPos(), enterEvent->windowPos(),
+ enterEvent->screenPos());
+ const bool ret = QCoreApplication::sendEvent(d->offscreenWindow, &mappedEvent);
+ e->setAccepted(mappedEvent.isAccepted());
+ return ret;
+ }
default:
break;
}
@@ -1597,6 +1672,9 @@ QQuickWindow *QQuickWidget::quickWindow() const
return d->offscreenWindow;
}
+/*!
+ \reimp
+ */
void QQuickWidget::paintEvent(QPaintEvent *event)
{
Q_D(QQuickWidget);
@@ -1607,13 +1685,15 @@ void QQuickWidget::paintEvent(QPaintEvent *event)
//Paint everything
painter.drawImage(rect(), d->softwareImage);
} else {
+ QTransform transform;
+ transform.scale(devicePixelRatioF(), devicePixelRatioF());
//Paint only the updated areas
- const auto rects = d->updateRegion.rects();
- for (auto targetRect : rects) {
- auto sourceRect = QRect(targetRect.topLeft() * devicePixelRatio(), targetRect.size() * devicePixelRatio());
+ QRegion targetRegion;
+ d->updateRegion.swap(targetRegion);
+ for (auto targetRect : targetRegion) {
+ auto sourceRect = transform.mapRect(QRectF(targetRect));
painter.drawImage(targetRect, d->softwareImage, sourceRect);
}
- d->updateRegion = QRegion();
}
}
}