aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickwindow.cpp')
-rw-r--r--src/quick/items/qquickwindow.cpp259
1 files changed, 170 insertions, 89 deletions
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 295ab9dc43..643e47c8a0 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -45,23 +45,16 @@
#include "qquickevents_p_p.h"
#include "qquickgraphicsdevice_p.h"
-#if QT_CONFIG(quick_draganddrop)
-#include <private/qquickdrag_p.h>
-#endif
-#include <private/qquickhoverhandler_p.h>
-#include <private/qquickpointerhandler_p.h>
-
#include <QtQuick/private/qsgrenderer_p.h>
#include <QtQuick/private/qsgplaintexture_p.h>
+#include <QtQuick/private/qquickpointerhandler_p.h>
#include <private/qsgrenderloop_p.h>
#include <private/qsgrhisupport_p.h>
#include <private/qquickrendercontrol_p.h>
#include <private/qquickanimatorcontroller_p.h>
-#include <private/qquickpointerhandler_p_p.h>
#include <private/qquickprofiler_p.h>
#include <private/qguiapplication_p.h>
-#include <QtGui/QInputMethod>
#include <private/qabstractanimation_p.h>
@@ -70,7 +63,6 @@
#include <QtGui/qmatrix4x4.h>
#include <QtGui/private/qevent_p.h>
#include <QtGui/private/qpointingdevice_p.h>
-#include <QtGui/qpa/qplatformtheme.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qabstractanimation.h>
#include <QtCore/QLibraryInfo>
@@ -96,12 +88,11 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcTablet, "qt.quick.tablet")
+Q_DECLARE_LOGGING_CATEGORY(lcMouse)
+Q_DECLARE_LOGGING_CATEGORY(lcTouch)
Q_LOGGING_CATEGORY(lcDirty, "qt.quick.dirty")
Q_LOGGING_CATEGORY(lcTransient, "qt.quick.window.transient")
-extern Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1);
-
bool QQuickWindowPrivate::defaultAlphaBuffer = false;
#if defined(QT_QUICK_DEFAULT_TEXT_RENDER_TYPE)
@@ -110,20 +101,6 @@ QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow:
QQuickWindow::TextRenderType QQuickWindowPrivate::textRenderType = QQuickWindow::QtTextRendering;
#endif
-void QQuickWindowPrivate::updateFocusItemTransform()
-{
-#if QT_CONFIG(im)
- Q_Q(QQuickWindow);
- QQuickItem *focus = q->activeFocusItem();
- if (focus && QGuiApplication::focusObject() == focus) {
- QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(focus);
- QGuiApplication::inputMethod()->setInputItemTransform(focusPrivate->itemToWindowTransform());
- QGuiApplication::inputMethod()->setInputItemRectangle(QRectF(0, 0, focusPrivate->width, focusPrivate->height));
- focus->updateInputMethod(Qt::ImInputItemClipRectangle);
- }
-#endif
-}
-
class QQuickWindowIncubationController : public QObject, public QQmlIncubationController
{
Q_OBJECT
@@ -280,9 +257,12 @@ void QQuickWindow::focusOutEvent(QFocusEvent *ev)
void QQuickWindow::focusInEvent(QFocusEvent *ev)
{
Q_D(QQuickWindow);
+ if (d->inDestructor)
+ return;
if (d->contentItem)
d->contentItem->setFocus(true, ev->reason());
- d->updateFocusItemTransform();
+ if (auto da = d->deliveryAgentPrivate())
+ da->updateFocusItemTransform();
}
#if QT_CONFIG(im)
@@ -408,7 +388,7 @@ void QQuickWindowPrivate::polishItems()
const bool isActiveFocusItem = (focusItem == QGuiApplication::focusObject());
const bool hasImEnabled = focusItem->inputMethodQuery(Qt::ImEnabled).toBool();
if (isActiveFocusItem && hasImEnabled && transformDirtyOnItemOrAncestor(focusItem))
- updateFocusItemTransform();
+ deliveryAgentPrivate()->updateFocusItemTransform();
}
#endif
}
@@ -719,47 +699,31 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
QQuickWindowPrivate::QQuickWindowPrivate()
: contentItem(nullptr)
- , activeFocusItem(nullptr)
-#if QT_CONFIG(cursor)
- , cursorItem(nullptr)
- , cursorHandler(nullptr)
-#endif
-#if QT_CONFIG(quick_draganddrop)
- , dragGrabber(nullptr)
-#endif
- , touchMouseId(-1)
- , touchMouseDevice(nullptr)
- , touchMousePressTimestamp(0)
, dirtyItemList(nullptr)
, devicePixelRatio(0)
, context(nullptr)
, renderer(nullptr)
, windowManager(nullptr)
, renderControl(nullptr)
- , pointerEventRecursionGuard(0)
, clearColor(Qt::white)
, persistentGraphics(true)
, persistentSceneGraph(true)
- , lastWheelEventAccepted(false)
, componentCompleted(true)
- , allowChildEventFiltering(true)
- , allowDoubleClick(true)
- , lastFocusReason(Qt::OtherFocusReason)
+ , inDestructor(false)
, incubationController(nullptr)
, hasActiveSwapchain(false)
, hasRenderableSwapchain(false)
, swapchainJustBecameRenderable(false)
{
-#if QT_CONFIG(quick_draganddrop)
- dragGrabber = new QQuickDragGrabber;
-#endif
}
QQuickWindowPrivate::~QQuickWindowPrivate()
{
+ inDestructor = true;
redirect.rt.reset(rhi, renderer);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->removeWindow(q_func());
+ deliveryAgent = nullptr;
}
void QQuickWindowPrivate::updateChildrenPalettes(const QPalette &parentPalette)
@@ -780,6 +744,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
Q_Q(QQuickWindow);
contentItem = new QQuickRootItem;
+ contentItem->setObjectName(q->objectName());
QQml_setParent_noEvent(contentItem, c);
QQmlEngine::setObjectOwnership(contentItem, QQmlEngine::CppOwnership);
QQuickItemPrivate *contentItemPrivate = QQuickItemPrivate::get(contentItem);
@@ -787,6 +752,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
contentItemPrivate->windowRefCount = 1;
contentItemPrivate->flags |= QQuickItem::ItemIsFocusScope;
contentItem->setSize(q->size());
+ deliveryAgent = new QQuickDeliveryAgent(contentItem);
visualizationMode = qgetenv("QSG_VISUALIZE");
renderControl = control;
@@ -839,7 +805,7 @@ void QQuickWindow::handleApplicationStateChanged(Qt::ApplicationState state)
{
Q_D(QQuickWindow);
if (state != Qt::ApplicationActive && d->contentItem)
- d->handleWindowDeactivate();
+ d->deliveryAgentPrivate()->handleWindowDeactivate(this);
}
/*!
@@ -871,8 +837,8 @@ void QQuickWindowPrivate::dirtyItem(QQuickItem *)
QQuickItem *QQuickWindow::mouseGrabberItem() const
{
Q_D(const QQuickWindow);
- auto epd = const_cast<QQuickWindowPrivate *>(d)->mousePointData();
- if (!epd && d->eventsInDelivery.isEmpty()) {
+ auto epd = const_cast<QQuickWindowPrivate *>(d)->deliveryAgentPrivate()->mousePointData();
+ if (!epd && d->deliveryAgentPrivate()->eventsInDelivery.isEmpty()) {
qCDebug(lcMouse, "mouse grabber ambiguous: no event is currently being delivered");
return qmlobject_cast<QQuickItem *>(QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice())->
firstPointExclusiveGrabber());
@@ -1134,7 +1100,7 @@ QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control
QQuickWindow::~QQuickWindow()
{
Q_D(QQuickWindow);
-
+ d->inDestructor = true;
if (d->renderControl) {
QQuickRenderControlPrivate::get(d->renderControl)->windowDestroyed();
} else if (d->windowManager) {
@@ -1143,12 +1109,11 @@ QQuickWindow::~QQuickWindow()
}
delete d->incubationController; d->incubationController = nullptr;
-#if QT_CONFIG(quick_draganddrop)
- delete d->dragGrabber; d->dragGrabber = nullptr;
-#endif
QQuickRootItem *root = d->contentItem;
d->contentItem = nullptr;
+ root->setParent(nullptr); // avoid QChildEvent delivery during deletion
delete root;
+ d->deliveryAgent = nullptr; // avoid forwarding events there during destruction
d->renderJobMutex.lock();
qDeleteAll(d->beforeSynchronizingJobs);
@@ -1305,9 +1270,6 @@ bool QQuickWindow::isPersistentSceneGraph() const
return d->persistentSceneGraph;
}
-
-
-
/*!
\qmlattachedproperty Item Window::contentItem
\since 5.4
@@ -1342,7 +1304,7 @@ QQuickItem *QQuickWindow::activeFocusItem() const
{
Q_D(const QQuickWindow);
- return d->activeFocusItem;
+ return d->deliveryAgentPrivate()->activeFocusItem;
}
/*!
@@ -1353,27 +1315,153 @@ QObject *QQuickWindow::focusObject() const
{
Q_D(const QQuickWindow);
- if (d->activeFocusItem)
- return d->activeFocusItem;
+ if (!d->inDestructor && d->deliveryAgentPrivate()->activeFocusItem)
+ return d->deliveryAgentPrivate()->activeFocusItem;
return const_cast<QQuickWindow*>(this);
}
/*! \reimp */
+bool QQuickWindow::event(QEvent *e)
+{
+ Q_D(QQuickWindow);
+
+ // bypass QWindow::event dispatching of input events: deliveryAgent takes care of it
+ QQuickDeliveryAgent *da = d->deliveryAgent;
+ if (e->isPointerEvent()) {
+ /*
+ When delivering update and release events to existing grabbers,
+ use the subscene delivery agent, if any. A possible scenario:
+ 1) Two touchpoints pressed on the main window: QQuickWindowPrivate::deliveryAgent delivers to QQuick3DViewport,
+ which does picking and finds two subscenes ("root" Items mapped onto two different 3D objects) to deliver it to.
+ 2) The QTouchEvent is split up so that each subscene sees points relevant to it.
+ 3) During delivery to either subscene, an item in the subscene grabs.
+ 4) The user moves finger(s) generating a move event: the correct grabber item needs to get the update
+ via the same subscene delivery agent from which it got the press, so that the coord transform will be done properly.
+ 5) Likewise with the touchpoint releases.
+ With single-point events (mouse, or only one finger) it's simplified: there can only be one subscene of interest;
+ for (pt : pe->points()) would only iterate once, so we might as well skip that logic.
+ */
+ auto pe = static_cast<QPointerEvent *>(e);
+ if (pe->pointCount() > 1) {
+ bool ret = false;
+ Q_ASSERT(QQuickDeliveryAgentPrivate::isTouchEvent(pe));
+ // Split up the multi-point event according to the relevant QQuickDeliveryAgent that should deliver to each existing grabber
+ // but send ungrabbed points to d->deliveryAgent()
+ QFlatMap<QQuickDeliveryAgent*, QList<QEventPoint>> deliveryAgentsNeedingPoints;
+ QEventPoint::States eventStates;
+ for (const auto &pt : pe->points()) {
+ eventStates |= pt.state();
+ auto *ptda = QQuickDeliveryAgent::grabberAgent(pe, pt);
+ if (!ptda)
+ ptda = da;
+ if (ptda) {
+ auto danpit = deliveryAgentsNeedingPoints.find(ptda);
+ if (danpit == deliveryAgentsNeedingPoints.end()) {
+ deliveryAgentsNeedingPoints.insert(ptda, QList<QEventPoint>() << pt);
+ } else {
+ danpit.value().append(pt);
+ }
+ }
+ }
+ // Make new touch events for each subscene, the same way QQuickItemPrivate::localizedTouchEvent() does it
+ for (auto daAndPoints : deliveryAgentsNeedingPoints) {
+ // if all points have the same state, set the event type accordingly
+ QEvent::Type eventType = pe->type();
+ switch (eventStates) {
+ case QEventPoint::State::Pressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case QEventPoint::State::Released:
+ eventType = QEvent::TouchEnd;
+ break;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+ QMutableTouchEvent te(eventType, pe->pointingDevice(), pe->modifiers(), daAndPoints.second);
+ te.setTimestamp(pe->timestamp());
+ te.accept();
+ qCDebug(lcTouch) << "subscene touch:" << daAndPoints.first << "shall now receive" << &te;
+ ret = daAndPoints.first->event(&te) || ret;
+ }
+ if (ret)
+ return true;
+ } else if (pe->pointCount()) {
+ // single-point event
+ if (auto *ptda = QQuickDeliveryAgent::grabberAgent(pe, pe->points().first()))
+ da = ptda;
+ }
+ // else if it has no points, it's probably a TouchCancel, and DeliveryAgent needs to handle it.
+ // TODO should we deliver to all DAs at once then, since we don't know which one should get it?
+ // or fix QTBUG-90851 so that the event always has points?
+ if (da && da->event(e))
+ return true;
+ } else if (e->isInputEvent()) {
+ if (da && da->event(e))
+ return true;
+ }
+
+ switch (e->type()) {
+ // a few more types that are not QInputEvents, but QQuickDeliveryAgent needs to handle them anyway
+ case QEvent::FocusAboutToChange:
+ case QEvent::Enter:
+ case QEvent::Leave:
+ case QEvent::InputMethod:
+ case QEvent::InputMethodQuery:
+#if QT_CONFIG(quick_draganddrop)
+ case QEvent::DragEnter:
+ case QEvent::DragLeave:
+ case QEvent::DragMove:
+ case QEvent::Drop:
+#endif
+ if (d->inDestructor)
+ return false;
+ if (da && da->event(e))
+ return true;
+ break;
+ case QEvent::LanguageChange:
+ if (d->contentItem)
+ QCoreApplication::sendEvent(d->contentItem, e);
+ break;
+ case QEvent::UpdateRequest:
+ if (d->windowManager)
+ d->windowManager->handleUpdateRequest(this);
+ break;
+ case QEvent::PlatformSurface:
+ if ((static_cast<QPlatformSurfaceEvent *>(e))->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) {
+ // Ensure that the rendering thread is notified before
+ // the QPlatformWindow is destroyed.
+ if (d->windowManager)
+ d->windowManager->hide(this);
+ }
+ break;
+ case QEvent::WindowDeactivate:
+ d->deliveryAgentPrivate()->handleWindowDeactivate(this);
+ break;
+ default:
+ break;
+ }
+
+ if (e->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest))
+ update();
+ else if (e->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
+ d->windowManager->handleContextCreationFailure(this);
+
+ return QWindow::event(e);
+}
+
+/*! \reimp */
void QQuickWindow::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(),
- e->modifiers());
- d->deliverKeyEvent(e);
+ d->deliveryAgentPrivate()->deliverKeyEvent(e);
}
/*! \reimp */
void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(),
- e->modifiers());
- d->deliverKeyEvent(e);
+ d->deliveryAgentPrivate()->deliverKeyEvent(e);
}
#if QT_CONFIG(wheelevent)
@@ -1381,18 +1469,7 @@ void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickWindow);
- Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
- event->angleDelta().x(), event->angleDelta().y());
-
- qCDebug(lcMouse) << event;
-
- //if the actual wheel event was accepted, accept the compatibility wheel event and return early
- if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate)
- return;
-
- event->ignore();
- d->deliverSinglePointEventUntilAccepted(event);
- d->lastWheelEventAccepted = event->isAccepted();
+ d->deliveryAgentPrivate()->deliverSinglePointEventUntilAccepted(event);
}
#endif // wheelevent
@@ -1401,9 +1478,7 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
void QQuickWindow::tabletEvent(QTabletEvent *event)
{
Q_D(QQuickWindow);
- qCDebug(lcTablet) << event;
- // TODO Qt 6: make sure TabletEnterProximity and TabletLeaveProximity are delivered here
- d->deliverPointerEvent(event);
+ d->deliveryAgentPrivate()->deliverPointerEvent(event);
}
#endif // tabletevent
@@ -1411,34 +1486,40 @@ void QQuickWindow::tabletEvent(QTabletEvent *event)
void QQuickWindow::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->handleMouseEvent(event);
+ d->deliveryAgentPrivate()->handleMouseEvent(event);
}
/*! \reimp */
void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->handleMouseEvent(event);
+ d->deliveryAgentPrivate()->handleMouseEvent(event);
}
/*! \reimp */
void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->handleMouseEvent(event);
+ d->deliveryAgentPrivate()->handleMouseEvent(event);
}
/*! \reimp */
void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
- d->handleMouseEvent(event);
+ d->deliveryAgentPrivate()->handleMouseEvent(event);
}
-#if QT_CONFIG(cursor)
-void QQuickWindowPrivate::updateCursor(const QPointF &scenePos)
+void QQuickWindowPrivate::flushFrameSynchronousEvents()
{
Q_Q(QQuickWindow);
+ deliveryAgentPrivate()->flushFrameSynchronousEvents(q);
+}
- auto cursorItemAndHandler = findCursorItemAndHandler(contentItem, scenePos);
-
+#if QT_CONFIG(cursor)
+void QQuickWindowPrivate::updateCursor(const QPointF &scenePos, QQuickItem *rootItem)
+{
+ Q_Q(QQuickWindow);
+ if (!rootItem)
+ rootItem = contentItem;
+ auto cursorItemAndHandler = findCursorItemAndHandler(rootItem, scenePos);
if (cursorItem != cursorItemAndHandler.first || cursorHandler != cursorItemAndHandler.second) {
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(q);
QWindow *window = renderWindow ? renderWindow : q;