5#include <QtCore/qdebug.h>
6#include <QtGui/private/qevent_p.h>
7#include <QtGui/private/qeventpoint_p.h>
8#include <QtGui/private/qguiapplication_p.h>
9#include <QtGui/qpa/qplatformtheme.h>
10#include <QtQml/private/qabstractanimationjob_p.h>
11#include <QtQuick/private/qquickdeliveryagent_p_p.h>
12#include <QtQuick/private/qquickhoverhandler_p.h>
13#include <QtQuick/private/qquickpointerhandler_p_p.h>
14#if QT_CONFIG(quick_draganddrop)
15#include <QtQuick/private/qquickdrag_p.h>
17#include <QtQuick/private/qquickitem_p.h>
18#include <QtQuick/private/qquickprofiler_p.h>
19#include <QtQuick/private/qquickrendercontrol_p.h>
20#include <QtQuick/private/qquickwindow_p.h>
22#include <QtCore/qpointer.h>
29Q_STATIC_LOGGING_CATEGORY(lcTouchCmprs,
"qt.quick.touch.compression")
30Q_LOGGING_CATEGORY(lcTouchTarget,
"qt.quick.touch.target")
31Q_LOGGING_CATEGORY(lcMouse,
"qt.quick.mouse")
32Q_STATIC_LOGGING_CATEGORY(lcMouseTarget,
"qt.quick.mouse.target")
33Q_STATIC_LOGGING_CATEGORY(lcTablet,
"qt.quick.tablet")
34Q_LOGGING_CATEGORY(lcPtr,
"qt.quick.pointer")
35Q_STATIC_LOGGING_CATEGORY(lcPtrLoc,
"qt.quick.pointer.localization")
36Q_STATIC_LOGGING_CATEGORY(lcWheelTarget,
"qt.quick.wheel.target")
37Q_LOGGING_CATEGORY(lcHoverTrace,
"qt.quick.hover.trace")
38Q_LOGGING_CATEGORY(lcHoverCursor,
"qt.quick.hover.cursor")
39Q_LOGGING_CATEGORY(lcFocus,
"qt.quick.focus")
40Q_STATIC_LOGGING_CATEGORY(lcContextMenu,
"qt.quick.contextmenu")
42extern 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);
44bool QQuickDeliveryAgentPrivate::subsceneAgentsExist(
false);
45QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentEventDeliveryAgent(
nullptr);
49 static int allowRightClick = -1;
50 if (allowRightClick < 0) {
52 allowRightClick = qEnvironmentVariableIntValue(
"QT_QUICK_ALLOW_SYNTHETIC_RIGHT_CLICK", &ok);
56 return allowRightClick != 0;
59void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type,
const QEventPoint &p,
const QTouchEvent *touchEvent, QMutableSinglePointEvent *mouseEvent)
61 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
62 QMutableSinglePointEvent ret(type, touchEvent->pointingDevice(), p,
63 (type == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton),
64 (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton),
65 touchEvent->modifiers(), Qt::MouseEventSynthesizedByQt);
66 ret.setAccepted(
true);
67 ret.setTimestamp(touchEvent->timestamp());
71 Q_ASSERT(mouseEvent->device() == touchEvent->device());
72 if (Q_UNLIKELY(mouseEvent->device()->type() == QInputDevice::DeviceType::Mouse))
73 qWarning() <<
"Unexpected: synthesized an indistinguishable mouse event" << mouseEvent;
77
78
79bool QQuickDeliveryAgentPrivate::isWithinDoubleClickInterval(ulong timeInterval)
81 return timeInterval <
static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
85
86
87bool QQuickDeliveryAgentPrivate::isWithinDoubleTapDistance(
const QPoint &distanceBetweenPresses)
89 auto square = [](qint64 v) {
return v * v; };
90 return square(distanceBetweenPresses.x()) + square(distanceBetweenPresses.y()) <
91 square(QGuiApplication::styleHints()->touchDoubleTapDistance());
94bool QQuickDeliveryAgentPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp,
const QPoint &newPressPos)
96 const bool doubleClicked = isDeliveringTouchAsMouse() &&
97 isWithinDoubleTapDistance(newPressPos - touchMousePressPos) &&
98 isWithinDoubleClickInterval(newPressEventTimestamp - touchMousePressTimestamp);
100 touchMousePressTimestamp = 0;
102 touchMousePressTimestamp = newPressEventTimestamp;
103 touchMousePressPos = newPressPos;
105 return doubleClicked;
108void QQuickDeliveryAgentPrivate::resetIfDoubleTapPrevented(
const QEventPoint &pressedPoint)
110 if (touchMousePressTimestamp > 0 &&
111 (!isWithinDoubleTapDistance(pressedPoint.globalPosition().toPoint() - touchMousePressPos) ||
112 !isWithinDoubleClickInterval(pressedPoint.timestamp() - touchMousePressTimestamp))) {
113 touchMousePressTimestamp = 0;
114 touchMousePressPos = QPoint();
119
120
121
122
123
124
125
126QPointerEvent *QQuickDeliveryAgentPrivate::eventInDelivery()
const
128 if (eventsInDelivery.isEmpty())
130 return eventsInDelivery.top();
134
135
136
137
138QPointingDevicePrivate::EventPointData *QQuickDeliveryAgentPrivate::mousePointData()
140 if (eventsInDelivery.isEmpty())
142 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(eventsInDelivery.top()->pointingDevice()));
143 return devPriv->pointById(isDeliveringTouchAsMouse() ? touchMouseId : 0);
146void QQuickDeliveryAgentPrivate::cancelTouchMouseSynthesis()
148 qCDebug(lcTouchTarget) <<
"id" << touchMouseId <<
"on" << touchMouseDevice;
150 touchMouseDevice =
nullptr;
153bool QQuickDeliveryAgentPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent)
155 Q_Q(QQuickDeliveryAgent);
156 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
157 auto device = pointerEvent->pointingDevice();
160 if (device->type() == QInputDevice::DeviceType::TouchPad && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
161 qCDebug(lcTouchTarget) << q <<
"skipping delivery of synth-mouse event from" << device;
166 QMutableTouchEvent event;
167 QQuickItemPrivate::get(item)->localizedTouchEvent(pointerEvent,
false, &event);
168 if (!event.points().size())
174 for (
auto &p : event.points()) {
176 if (touchMouseId == -1 && p.state() & QEventPoint::State::Pressed) {
177 QPointF pos = item->mapFromScene(p.scenePosition());
180 if (!item->contains(pos))
183 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << item;
184 QMutableSinglePointEvent mousePress;
185 touchToMouseEvent(QEvent::MouseButtonPress, p, &event, &mousePress);
188 QCoreApplication::sendEvent(item, &mousePress);
189 event.setAccepted(mousePress.isAccepted());
190 if (mousePress.isAccepted()) {
191 touchMouseDevice = device;
192 touchMouseId = p.id();
193 const auto &pt = mousePress.point(0);
194 if (!mousePress.exclusiveGrabber(pt))
195 mousePress.setExclusiveGrabber(pt, item);
197 if (checkIfDoubleTapped(event.timestamp(), p.globalPosition().toPoint())) {
200 QMutableSinglePointEvent mouseDoubleClick;
201 touchToMouseEvent(QEvent::MouseButtonDblClick, p, &event, &mouseDoubleClick);
202 QCoreApplication::sendEvent(item, &mouseDoubleClick);
203 event.setAccepted(mouseDoubleClick.isAccepted());
204 if (!mouseDoubleClick.isAccepted())
205 cancelTouchMouseSynthesis();
213 }
else if (touchMouseDevice == device && p.id() == touchMouseId) {
214 if (p.state() & QEventPoint::State::Updated) {
215 if (touchMousePressTimestamp != 0) {
216 if (!isWithinDoubleTapDistance(p.globalPosition().toPoint() - touchMousePressPos))
217 touchMousePressTimestamp = 0;
219 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
220 QMutableSinglePointEvent me;
221 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
222 QCoreApplication::sendEvent(item, &me);
223 event.setAccepted(me.isAccepted());
225 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << mouseGrabberItem;
226 return event.isAccepted();
231 QMutableSinglePointEvent me;
232 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
233 if (lastMousePosition.isNull())
234 lastMousePosition = me.scenePosition();
235 QPointF last = lastMousePosition;
236 lastMousePosition = me.scenePosition();
238 deliverHoverEvent(me.scenePosition(), last, me.modifiers(), me.timestamp());
241 }
else if (p.state() & QEventPoint::State::Released) {
243 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
244 QMutableSinglePointEvent me;
245 touchToMouseEvent(QEvent::MouseButtonRelease, p, &event, &me);
246 QCoreApplication::sendEvent(item, &me);
248 if (item->acceptHoverEvents() && p.globalPosition() != QGuiApplicationPrivate::lastCursorPosition) {
249 QPointF localMousePos(qInf(), qInf());
250 if (QWindow *w = item->window())
251 localMousePos = item->mapFromScene(w->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition));
252 QMouseEvent mm(QEvent::MouseMove, localMousePos, QGuiApplicationPrivate::lastCursorPosition,
253 Qt::NoButton, Qt::NoButton, event.modifiers());
254 QCoreApplication::sendEvent(item, &mm);
256 if (pointerEvent->exclusiveGrabber(p) == mouseGrabberItem)
257 pointerEvent->setExclusiveGrabber(p,
nullptr);
259 cancelTouchMouseSynthesis();
260 return me.isAccepted();
270
271
272
273
274
275
276
277
278void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber,
bool mouse,
bool touch,
bool cancel)
280 Q_Q(QQuickDeliveryAgent);
281 if (eventsInDelivery.isEmpty()) {
283 for (
auto dev : knownPointingDevices) {
284 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(dev));
285 devPriv->removeGrabber(grabber, cancel);
289 auto eventInDelivery = eventsInDelivery.top();
290 if (Q_LIKELY(mouse) && eventInDelivery) {
291 auto epd = mousePointData();
292 if (epd && epd->exclusiveGrabber == grabber && epd->exclusiveGrabberContext.data() == q) {
293 QQuickItem *oldGrabber = qobject_cast<QQuickItem *>(epd->exclusiveGrabber);
294 qCDebug(lcMouseTarget) <<
"removeGrabber" << oldGrabber <<
"-> null";
295 eventInDelivery->setExclusiveGrabber(epd->eventPoint,
nullptr);
298 if (Q_LIKELY(touch)) {
300 const auto touchDevices = QPointingDevice::devices();
301 for (
auto device : touchDevices) {
302 if (device->type() != QInputDevice::DeviceType::TouchScreen)
304 if (QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(
static_cast<
const QPointingDevice *>(device)))->
305 removeExclusiveGrabber(eventInDelivery, grabber))
309 grabber->touchUngrabEvent();
314
315
316
317
318
319
320
321
322
323
324
325void QQuickDeliveryAgentPrivate::clearGrabbers(QPointerEvent *pointerEvent)
327 if (pointerEvent->isEndEvent()
328 && !(isTabletEvent(pointerEvent)
329 && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
330 || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
331 if (pointerEvent->isSinglePointEvent()) {
332 if (
static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
333 auto &firstPt = pointerEvent->point(0);
334 pointerEvent->setExclusiveGrabber(firstPt,
nullptr);
335 pointerEvent->clearPassiveGrabbers(firstPt);
338 for (
auto &point : pointerEvent->points()) {
339 if (point.state() == QEventPoint::State::Released) {
340 pointerEvent->setExclusiveGrabber(point,
nullptr);
341 pointerEvent->clearPassiveGrabbers(point);
349
350
351
352
353void QQuickDeliveryAgentPrivate::translateTouchEvent(QTouchEvent *touchEvent)
355 for (qsizetype i = 0; i != touchEvent->pointCount(); ++i) {
356 auto &pt = touchEvent->point(i);
357 QMutableEventPoint::setScenePosition(pt, pt.position());
364 const QWindow *focusWindow = QGuiApplication::focusWindow();
365 return win == focusWindow || QQuickRenderControlPrivate::isRenderWindowFor(win, focusWindow) || !focusWindow;
370 QQuickItem *parentItem = item->parentItem();
372 if (parentItem && parentItem->flags() & QQuickItem::ItemIsFocusScope)
373 return findFurthestFocusScopeAncestor(parentItem);
380static inline bool singleWindowOnScreen(QQuickWindow *win)
382 const QWindowList windowList = QGuiApplication::allWindows();
383 for (
int i = 0; i < windowList.count(); i++) {
384 QWindow *ii = windowList.at(i);
387 if (ii->screen() == win->screen())
396
397
398
399
400void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item,
401 Qt::FocusReason reason, FocusOptions options)
403 Q_Q(QQuickDeliveryAgent);
405 Q_ASSERT(scope || item == rootItem);
407 qCDebug(lcFocus) << q <<
"focus" << item <<
"in scope" << scope;
409 qCDebug(lcFocus) <<
" scopeSubFocusItem:" << QQuickItemPrivate::get(scope)->subFocusItem;
411 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) :
nullptr;
412 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
414 QQuickItem *oldActiveFocusItem =
nullptr;
415 QQuickItem *currentActiveFocusItem = activeFocusItem;
416 QQuickItem *newActiveFocusItem =
nullptr;
417 bool sendFocusIn =
false;
419 lastFocusReason = reason;
421 QVarLengthArray<QQuickItem *, 20> changed;
424 if (item == rootItem || scopePrivate->activeFocus) {
425 oldActiveFocusItem = activeFocusItem;
426 if (item->isEnabled()) {
427 newActiveFocusItem = item;
428 while (newActiveFocusItem->isFocusScope()
429 && newActiveFocusItem->scopedFocusItem()
430 && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
431 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
434 newActiveFocusItem = scope;
437 if (oldActiveFocusItem) {
439 QGuiApplication::inputMethod()->commit();
442 activeFocusItem =
nullptr;
444 QQuickItem *afi = oldActiveFocusItem;
445 while (afi && afi != scope) {
446 if (QQuickItemPrivate::get(afi)->activeFocus) {
447 QQuickItemPrivate::get(afi)->activeFocus =
false;
450 afi = afi->parentItem();
455 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
456 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
457 if (oldSubFocusItem) {
458 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
460 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
461 changed << oldSubFocusItem;
464 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
true);
467 if (!(options & DontChangeFocusProperty)) {
468 if (item != rootItem || windowHasFocus(rootItem->window())
472 || singleWindowOnScreen(rootItem->window())
475 itemPrivate->focus =
true;
476 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
481 if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) {
482 activeFocusItem = newActiveFocusItem;
484 QQuickItemPrivate::get(newActiveFocusItem)->activeFocus =
true;
485 changed << newActiveFocusItem;
487 QQuickItem *afi = newActiveFocusItem->parentItem();
488 while (afi && afi != scope) {
489 if (afi->isFocusScope()) {
490 QQuickItemPrivate::get(afi)->activeFocus =
true;
493 afi = afi->parentItem();
495 updateFocusItemTransform();
501 if (oldActiveFocusItem) {
502 QFocusEvent event(QEvent::FocusOut, reason);
503 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
507 if (sendFocusIn && activeFocusItem == newActiveFocusItem) {
508 QFocusEvent event(QEvent::FocusIn, reason);
509 QCoreApplication::sendEvent(newActiveFocusItem, &event);
512 if (activeFocusItem != currentActiveFocusItem)
513 emit rootItem->window()->focusObjectChanged(activeFocusItem);
515 if (!changed.isEmpty())
516 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
517 if (isSubsceneAgent) {
518 auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent;
519 qCDebug(lcFocus) <<
" delegating setFocusInScope to" << da;
527 QQuickItem *ancestorFS = findFurthestFocusScopeAncestor(item);
528 if (ancestorFS != item)
529 options |= QQuickDeliveryAgentPrivate::DontChangeSubFocusItem;
530 QQuickWindowPrivate::get(rootItem->window())->deliveryAgentPrivate()->setFocusInScope(da->rootItem(), item, reason, options);
532 if (oldActiveFocusItem == activeFocusItem)
533 qCDebug(lcFocus) <<
" activeFocusItem remains" << activeFocusItem <<
"in" << q;
535 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
538void QQuickDeliveryAgentPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions options)
541 Q_ASSERT(scope || item == rootItem);
542 Q_Q(QQuickDeliveryAgent);
543 qCDebug(lcFocus) << q <<
"clear focus" << item <<
"in scope" << scope;
545 QQuickItemPrivate *scopePrivate =
nullptr;
547 scopePrivate = QQuickItemPrivate::get(scope);
548 if ( !scopePrivate->subFocusItem )
552 QQuickItem *currentActiveFocusItem = activeFocusItem;
553 QQuickItem *oldActiveFocusItem =
nullptr;
554 QQuickItem *newActiveFocusItem =
nullptr;
556 lastFocusReason = reason;
558 QVarLengthArray<QQuickItem *, 20> changed;
560 Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
563 if (item == rootItem || scopePrivate->activeFocus) {
564 oldActiveFocusItem = activeFocusItem;
565 newActiveFocusItem = scope;
568 QGuiApplication::inputMethod()->commit();
571 activeFocusItem =
nullptr;
573 if (oldActiveFocusItem) {
574 QQuickItem *afi = oldActiveFocusItem;
575 while (afi && afi != scope) {
576 if (QQuickItemPrivate::get(afi)->activeFocus) {
577 QQuickItemPrivate::get(afi)->activeFocus =
false;
580 afi = afi->parentItem();
585 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
586 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
587 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
588 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
590 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
591 changed << oldSubFocusItem;
594 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
false);
596 }
else if (!(options & DontChangeFocusProperty)) {
597 QQuickItemPrivate *priv = QQuickItemPrivate::get(item);
599 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
603 if (newActiveFocusItem) {
604 Q_ASSERT(newActiveFocusItem == scope);
605 activeFocusItem = scope;
606 updateFocusItemTransform();
611 if (oldActiveFocusItem) {
612 QFocusEvent event(QEvent::FocusOut, reason);
613 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
617 if (newActiveFocusItem && activeFocusItem == newActiveFocusItem) {
618 QFocusEvent event(QEvent::FocusIn, reason);
619 QCoreApplication::sendEvent(newActiveFocusItem, &event);
622 QQuickWindow *rootItemWindow = rootItem->window();
623 if (activeFocusItem != currentActiveFocusItem && rootItemWindow)
624 emit rootItemWindow->focusObjectChanged(activeFocusItem);
626 if (!changed.isEmpty())
627 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
628 if (isSubsceneAgent && rootItemWindow) {
629 auto da = QQuickWindowPrivate::get(rootItemWindow)->deliveryAgent;
630 qCDebug(lcFocus) <<
" delegating clearFocusInScope to" << da;
631 QQuickWindowPrivate::get(rootItemWindow)->deliveryAgentPrivate()->clearFocusInScope(da->rootItem(), item, reason, options);
633 if (oldActiveFocusItem == activeFocusItem)
634 qCDebug(lcFocus) <<
"activeFocusItem remains" << activeFocusItem <<
"in" << q;
636 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
639void QQuickDeliveryAgentPrivate::clearFocusObject()
641 if (activeFocusItem == rootItem)
644 clearFocusInScope(rootItem, QQuickItemPrivate::get(rootItem)->subFocusItem, Qt::OtherFocusReason);
647void QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(QQuickItem **items,
int remaining, Qt::FocusReason reason)
649 QPointer<QQuickItem> item(*items);
652 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
654 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
655 itemPrivate->notifiedFocus = itemPrivate->focus;
656 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
657 emit item->focusChanged(itemPrivate->focus);
660 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
661 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
662 itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged,
bool(itemPrivate->activeFocus));
663 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
664 emit item->activeFocusChanged(itemPrivate->activeFocus);
669 notifyFocusChangesRecur(items + 1, remaining - 1, reason);
672bool QQuickDeliveryAgentPrivate::clearHover(ulong timestamp)
674 if (hoverItems.isEmpty())
677 QQuickWindow *window = rootItem->window();
681 const auto globalPos = QGuiApplicationPrivate::lastCursorPosition;
682 const QPointF lastPos = window->mapFromGlobal(globalPos);
683 const auto modifiers = QGuiApplication::keyboardModifiers();
691 for (
auto it = hoverItems.cbegin(); it != hoverItems.cend(); ++it) {
692 if (
const auto &item = it.key()) {
693 deliverHoverEventToItem(item, item->mapFromScene(lastPos), lastPos, lastPos,
694 globalPos, modifiers, timestamp, HoverChange::Clear);
695 Q_ASSERT(([
this, item]{
696 const auto &it2 = std::as_const(hoverItems).find(item);
697 return it2 == hoverItems.cend() || it2.value() == 0;
705void QQuickDeliveryAgentPrivate::updateFocusItemTransform()
708 if (activeFocusItem && QGuiApplication::focusObject() == activeFocusItem) {
709 QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(activeFocusItem);
710 QGuiApplication::inputMethod()->setInputItemTransform(focusPrivate->itemToWindowTransform());
711 QGuiApplication::inputMethod()->setInputItemRectangle(QRectF(0, 0, focusPrivate->width, focusPrivate->height));
712 activeFocusItem->updateInputMethod(Qt::ImInputItemClipRectangle);
718
719
720
721QQuickItem *QQuickDeliveryAgentPrivate::focusTargetItem()
const
724 return activeFocusItem;
727 QQuickItem *targetItem = rootItem;
729 while (targetItem->isFocusScope()
730 && targetItem->scopedFocusItem()
731 && targetItem->scopedFocusItem()->isEnabled()) {
732 targetItem = targetItem->scopedFocusItem();
739
740
741
742
743
744QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(
const QQuickItem *item)
746 if (currentEventDeliveryAgent)
747 return currentEventDeliveryAgent;
749 return QQuickItemPrivate::get(
const_cast<QQuickItem *>(item))->deliveryAgent();
754
755
756
757
758QQuickDeliveryAgent::QQuickDeliveryAgent(QQuickItem *rootItem)
759 : QObject(*
new QQuickDeliveryAgentPrivate(rootItem), rootItem)
763QQuickDeliveryAgent::~QQuickDeliveryAgent()
767QQuickDeliveryAgent::Transform::~Transform()
772
773
774
775QQuickItem *QQuickDeliveryAgent::rootItem()
const
777 Q_D(
const QQuickDeliveryAgent);
782
783
784
785
786QQuickDeliveryAgent::Transform *QQuickDeliveryAgent::sceneTransform()
const
788 Q_D(
const QQuickDeliveryAgent);
789 return d->sceneTransform;
793
794
795
796
797void QQuickDeliveryAgent::setSceneTransform(QQuickDeliveryAgent::Transform *transform)
799 Q_D(QQuickDeliveryAgent);
800 if (d->sceneTransform == transform)
802 qCDebug(lcPtr) <<
this << d->sceneTransform <<
"->" << transform;
803 if (d->sceneTransform)
804 delete d->sceneTransform;
805 d->sceneTransform = transform;
809
810
811
812
813
814
815bool QQuickDeliveryAgent::event(QEvent *ev)
817 Q_D(QQuickDeliveryAgent);
818 d->currentEventDeliveryAgent =
this;
819 auto cleanup = qScopeGuard([d] { d->currentEventDeliveryAgent =
nullptr; });
821 switch (ev->type()) {
822 case QEvent::MouseButtonPress:
823 case QEvent::MouseButtonRelease:
824 case QEvent::MouseButtonDblClick:
825 case QEvent::MouseMove: {
826 QMouseEvent *me =
static_cast<QMouseEvent*>(ev);
827 d->handleMouseEvent(me);
830 case QEvent::HoverEnter:
831 case QEvent::HoverLeave:
832 case QEvent::HoverMove: {
833 QHoverEvent *he =
static_cast<QHoverEvent*>(ev);
834 bool accepted = d->deliverHoverEvent(he->scenePosition(),
835 he->points().first().sceneLastPosition(),
836 he->modifiers(), he->timestamp());
837 d->lastMousePosition = he->scenePosition();
838 he->setAccepted(accepted);
840 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(d->sceneTransform ?
841 d->sceneTransform->map(he->scenePosition()) : he->scenePosition(), d->rootItem);
845 case QEvent::TouchBegin:
846 case QEvent::TouchUpdate:
847 case QEvent::TouchEnd: {
848 QTouchEvent *touch =
static_cast<QTouchEvent*>(ev);
849 d->handleTouchEvent(touch);
850 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
857 case QEvent::TouchCancel:
859 return d->deliverTouchCancelEvent(
static_cast<QTouchEvent*>(ev));
861 case QEvent::Enter: {
864 QEnterEvent *enter =
static_cast<QEnterEvent*>(ev);
865 const auto scenePos = enter->scenePosition();
866 qCDebug(lcHoverTrace) <<
this <<
"sending hover event due to QEnterEvent" << enter;
867 bool accepted = d->deliverHoverEvent(scenePos,
868 enter->points().first().sceneLastPosition(),
869 enter->modifiers(), enter->timestamp());
870 d->lastMousePosition = scenePos;
872 Q_ASSERT(enter->scenePosition() == scenePos);
873 enter->setAccepted(accepted);
875 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(enter->scenePosition(), d->rootItem);
881 d->lastMousePosition = QPointF();
883#if QT_CONFIG(quick_draganddrop)
884 case QEvent::DragEnter:
885 case QEvent::DragLeave:
886 case QEvent::DragMove:
888 d->deliverDragEvent(d->dragGrabber, ev);
891 case QEvent::FocusAboutToChange:
893 if (d->activeFocusItem)
894 qGuiApp->inputMethod()->commit();
897#if QT_CONFIG(gestures)
898 case QEvent::NativeGesture:
899 d->deliverSinglePointEventUntilAccepted(
static_cast<QPointerEvent *>(ev));
902 case QEvent::ShortcutOverride:
903 d->deliverKeyEvent(
static_cast<QKeyEvent *>(ev));
905 case QEvent::InputMethod:
906 case QEvent::InputMethodQuery:
908 QQuickItem *target = d->focusTargetItem();
910 QCoreApplication::sendEvent(target, ev);
913#if QT_CONFIG(wheelevent)
914 case QEvent::Wheel: {
915 auto event =
static_cast<QWheelEvent *>(ev);
916 qCDebug(lcMouse) << event;
919 if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate)
923 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
924 event->angleDelta().x(), event->angleDelta().y());
925 d->deliverSinglePointEventUntilAccepted(event);
926 d->lastWheelEventAccepted = event->isAccepted();
930#if QT_CONFIG(tabletevent)
931 case QEvent::TabletPress:
932 case QEvent::TabletMove:
933 case QEvent::TabletRelease:
935 auto *tabletEvent =
static_cast<QTabletEvent *>(ev);
936 d->deliverPointerEvent(tabletEvent);
938 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(tabletEvent->scenePosition(), d->rootItem);
943#ifndef QT_NO_CONTEXTMENU
944 case QEvent::ContextMenu:
945 d->deliverContextMenuEvent(
static_cast<QContextMenuEvent *>(ev));
949 Q_ASSERT(
static_cast<QTimerEvent *>(ev)->timerId() == d->frameSynchronousDelayTimer.timerId());
950 d->frameSynchronousDelayTimer.stop();
951 d->flushFrameSynchronousEvents(d->rootItem->window());
960void QQuickDeliveryAgentPrivate::deliverKeyEvent(QKeyEvent *e)
962 if (activeFocusItem) {
963 const bool keyPress = (e->type() == QEvent::KeyPress);
965 case QEvent::KeyPress:
966 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(), e->modifiers());
968 case QEvent::KeyRelease:
969 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(), e->modifiers());
975 QQuickItem *item = activeFocusItem;
978 if (keyPress && e->spontaneous() ==
false)
979 qt_sendShortcutOverrideEvent(item, e->timestamp(),
980 e->key(), e->modifiers(), e->text(),
981 e->isAutoRepeat(), e->count());
984 Q_ASSERT(e->type() != QEvent::ShortcutOverride || !e->isAccepted());
985 if (e->type() != QEvent::ShortcutOverride)
987 QCoreApplication::sendEvent(item, e);
988 }
while (!e->isAccepted() && (item = item->parentItem()));
992QQuickDeliveryAgentPrivate::QQuickDeliveryAgentPrivate(QQuickItem *root) :
996 isSubsceneAgent(!qmlobject_cast<QQuickRootItem *>(rootItem))
998#if QT_CONFIG(quick_draganddrop)
999 dragGrabber =
new QQuickDragGrabber;
1001 if (isSubsceneAgent)
1002 subsceneAgentsExist =
true;
1003 const auto interval = qEnvironmentVariableIntegerValue(
"QT_QUICK_FRAME_SYNCHRONOUS_HOVER_INTERVAL");
1004 if (interval.has_value()) {
1005 qCDebug(lcHoverTrace) <<
"frame-synchronous hover interval" << interval;
1006 frameSynchronousHoverInterval =
int(interval.value());
1008 if (frameSynchronousHoverInterval > 0)
1009 frameSynchronousHoverTimer.start();
1012QQuickDeliveryAgentPrivate::~QQuickDeliveryAgentPrivate()
1014#if QT_CONFIG(quick_draganddrop)
1016 dragGrabber =
nullptr;
1018 delete sceneTransform;
1022
1023
1024
1025
1026
1027
1028QPointerEvent *QQuickDeliveryAgentPrivate::clonePointerEvent(QPointerEvent *event, std::optional<QPointF> transformedLocalPos)
1030 QPointerEvent *ret = event->clone();
1031 QEventPoint &point = ret->point(0);
1032 QMutableEventPoint::detach(point);
1033 QMutableEventPoint::setTimestamp(point, event->timestamp());
1034 if (transformedLocalPos)
1035 QMutableEventPoint::setPosition(point, *transformedLocalPos);
1040void QQuickDeliveryAgentPrivate::deliverToPassiveGrabbers(
const QList<QPointer <QObject> > &passiveGrabbers,
1041 QPointerEvent *pointerEvent)
1043 const QList<QObject *> &eventDeliveryTargets =
1044 QQuickPointerHandlerPrivate::deviceDeliveryTargets(pointerEvent->device());
1045 QVarLengthArray<std::pair<QQuickItem *,
bool>, 4> sendFilteredPointerEventResult;
1046 hasFiltered.clear();
1047 for (QObject *grabberObject : passiveGrabbers) {
1049 if (Q_UNLIKELY(!grabberObject))
1052 if (QQuickPointerHandler *handler = qobject_cast<QQuickPointerHandler *>(grabberObject)) {
1053 if (handler && !eventDeliveryTargets.contains(handler)) {
1054 bool alreadyFiltered =
false;
1055 QQuickItem *par = handler->parentItem();
1058 auto it = std::find_if(sendFilteredPointerEventResult.begin(), sendFilteredPointerEventResult.end(),
1059 [par](
const std::pair<QQuickItem *,
bool> &pair) {
return pair.first == par; });
1060 if (it != sendFilteredPointerEventResult.end()) {
1063 alreadyFiltered = it->second;
1065 alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par);
1066 sendFilteredPointerEventResult << std::make_pair(par, alreadyFiltered);
1068 if (!alreadyFiltered) {
1070 localizePointerEvent(pointerEvent, par);
1071 handler->handlePointerEvent(pointerEvent);
1074 }
else if (QQuickItem *grabberItem =
static_cast<QQuickItem *>(grabberObject)) {
1076 if (QQuickItem *excGrabber =
static_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(pointerEvent->point(0)))) {
1077 if ((isMouseEvent(pointerEvent) && excGrabber->keepMouseGrab())
1078 || (isTouchEvent(pointerEvent) && excGrabber->keepTouchGrab())) {
1082 localizePointerEvent(pointerEvent, grabberItem);
1083 QCoreApplication::sendEvent(grabberItem, pointerEvent);
1084 pointerEvent->accept();
1089bool QQuickDeliveryAgentPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1090 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1091 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp)
1093 QHoverEvent hoverEvent(type, scenePos, globalPos, lastScenePos, modifiers);
1094 hoverEvent.setTimestamp(timestamp);
1095 hoverEvent.setAccepted(
true);
1096 QEventPoint &point = hoverEvent.point(0);
1097 QMutableEventPoint::setPosition(point, localPos);
1098 if (Q_LIKELY(item->window()))
1099 QMutableEventPoint::setGlobalLastPosition(point, item->window()->mapToGlobal(lastScenePos));
1101 hasFiltered.clear();
1102 if (sendFilteredMouseEvent(&hoverEvent, item, item->parentItem()))
1105 QCoreApplication::sendEvent(item, &hoverEvent);
1107 return hoverEvent.isAccepted();
1111
1112
1113
1114
1116bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
1117 const QPointF &scenePos,
const QPointF &lastScenePos,
1118 Qt::KeyboardModifiers modifiers, ulong timestamp)
1136 const bool subtreeHoverEnabled = QQuickItemPrivate::get(rootItem)->subtreeHoverEnabled;
1137 const bool itemsWasHovered = !hoverItems.isEmpty();
1139 if (!subtreeHoverEnabled && !itemsWasHovered)
1144 if (subtreeHoverEnabled) {
1145 hoveredLeafItemFound =
false;
1146 QQuickPointerHandlerPrivate::deviceDeliveryTargets(QPointingDevice::primaryPointingDevice()).clear();
1147 deliverHoverEventRecursive(rootItem, scenePos, scenePos, lastScenePos,
1148 rootItem->mapToGlobal(scenePos), modifiers, timestamp);
1152 for (
auto it = hoverItems.begin(); it != hoverItems.end();) {
1153 const auto &[item, hoverId] = *it;
1154 if (hoverId == currentHoverId) {
1161 if (item && hoverId != 0)
1162 deliverHoverEventToItem(item, item->mapFromScene(scenePos), scenePos, lastScenePos,
1163 QGuiApplicationPrivate::lastCursorPosition, modifiers, timestamp, HoverChange::Clear);
1164 it = hoverItems.erase(it);
1168 const bool itemsAreHovered = !hoverItems.isEmpty();
1169 return itemsWasHovered || itemsAreHovered;
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(QQuickItem *item,
1209 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
const QPointF &globalPos,
1210 Qt::KeyboardModifiers modifiers, ulong timestamp)
1212 const QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1213 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1214 const bool hadChildrenChanged = itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged;
1216 for (
int ii = children.size() - 1; ii >= 0; --ii) {
1220 if (!hadChildrenChanged && Q_UNLIKELY(itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged))
1222 QQuickItem *child = children.at(ii);
1223 const QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
1225 if (!child->isVisible() || childPrivate->culled)
1227 if (!childPrivate->subtreeHoverEnabled)
1230 QTransform childToParent;
1231 childPrivate->itemToParentTransform(&childToParent);
1232 const QPointF childLocalPos = childToParent.inverted().map(localPos);
1237 if (childPrivate->effectivelyClipsEventHandlingChildren() &&
1238 !childPrivate->eventHandlingBounds().contains(childLocalPos)) {
1239#ifdef QT_BUILD_INTERNAL
1240 ++QQuickItemPrivate::effectiveClippingSkips_counter;
1246 const bool accepted = deliverHoverEventRecursive(child, childLocalPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1251 if (hoveredLeafItemFound) {
1259 return deliverHoverEventToItem(item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp, HoverChange::Set);
1263
1264
1265
1266
1267
1268
1269
1270bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1271 QQuickItem *item,
const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1272 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp, HoverChange hoverChange)
1274 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1275 const bool isHovering = item->contains(localPos);
1276 const auto hoverItemIterator = hoverItems.find(item);
1277 const bool wasHovering = hoverItemIterator != hoverItems.end() && hoverItemIterator.value() != 0;
1279 qCDebug(lcHoverTrace) <<
"item:" << item <<
"scene pos:" << scenePos <<
"localPos:" << localPos
1280 <<
"wasHovering:" << wasHovering <<
"isHovering:" << isHovering;
1282 bool accepted =
false;
1287 if (itemPrivate->hoverEnabled && isHovering && hoverChange == HoverChange::Set) {
1292 hoveredLeafItemFound =
true;
1293 if (hoverItemIterator != hoverItems.end())
1294 hoverItemIterator.value() = currentHoverId;
1296 hoverItems[item] = currentHoverId;
1299 accepted = sendHoverEvent(QEvent::HoverMove, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1301 accepted = sendHoverEvent(QEvent::HoverEnter, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1302 }
else if (wasHovering) {
1304 hoverItemIterator.value() = 0;
1305 sendHoverEvent(QEvent::HoverLeave, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1308 if (!itemPrivate->hasPointerHandlers())
1318 if (hoverChange == HoverChange::Clear) {
1320 QHoverEvent hoverEvent(QEvent::HoverLeave, scenePos, globalPos, lastScenePos, modifiers);
1321 hoverEvent.setTimestamp(timestamp);
1323 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1324 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1325 if (!hh->isHovered())
1327 hoverEvent.setAccepted(
true);
1328 QCoreApplication::sendEvent(hh, &hoverEvent);
1332 QMouseEvent hoverEvent(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, Qt::NoButton, modifiers);
1333 hoverEvent.setTimestamp(timestamp);
1335 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1336 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1339 hoverEvent.setAccepted(
true);
1340 hh->handlePointerEvent(&hoverEvent);
1341 if (hh->isHovered()) {
1344 hoveredLeafItemFound =
true;
1345 if (hoverItemIterator != hoverItems.end())
1346 hoverItemIterator.value() = currentHoverId;
1348 hoverItems[item] = currentHoverId;
1349 if (hh->isBlocking()) {
1350 qCDebug(lcHoverTrace) <<
"skipping rest of hover delivery due to blocking" << hh;
1364bool QQuickDeliveryAgentPrivate::deliverSinglePointEventUntilAccepted(QPointerEvent *event)
1366 Q_ASSERT(event->points().size() == 1);
1367 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
1368 QEventPoint &point = event->point(0);
1369 QList<QQuickItem *> targetItems = pointerTargets(rootItem, event, point,
false,
false);
1370 point.setAccepted(
false);
1375 for (
const auto &passiveGrabber : event->passiveGrabbers(point)) {
1376 if (
auto *grabberItem = qobject_cast<QQuickItem *>(passiveGrabber)) {
1377 if (targetItems.contains(grabberItem))
1379 localizePointerEvent(event, grabberItem);
1380 QCoreApplication::sendEvent(grabberItem, event);
1387 for (QQuickItem *item : targetItems) {
1388 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1389 localizePointerEvent(event, item);
1391 itemPrivate->handlePointerEvent(event);
1392 if (point.isAccepted())
1395 QCoreApplication::sendEvent(item, event);
1396 if (event->isAccepted()) {
1397 qCDebug(lcWheelTarget) << event <<
"->" << item;
1405bool QQuickDeliveryAgentPrivate::deliverTouchCancelEvent(QTouchEvent *event)
1407 qCDebug(lcTouch) << event;
1412 const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(event->pointingDevice()))->
1413 sendTouchCancelEvent(event);
1415 cancelTouchMouseSynthesis();
1420void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent()
1425 std::unique_ptr<QTouchEvent> e(std::move(delayedTouch));
1426 qCDebug(lcTouchCmprs) <<
"delivering" << e.get();
1427 compressedTouchCount = 0;
1428 deliverPointerEvent(e.get());
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
1443 Q_Q(QQuickDeliveryAgent);
1444 qCDebug(lcFocus) <<
"deactivated" << win->title();
1445 const auto inputDevices = QInputDevice::devices();
1446 for (
auto device : inputDevices) {
1447 if (
auto pointingDevice = qobject_cast<
const QPointingDevice *>(device)) {
1448 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(pointingDevice));
1449 for (
auto epd : devPriv->activePoints.values()) {
1450 if (!epd.exclusiveGrabber.isNull()) {
1451 bool relevant =
false;
1452 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(epd.exclusiveGrabber.data()))
1453 relevant = (item->window() == win);
1454 else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(epd.exclusiveGrabber.data())) {
1455 if (handler->parentItem())
1456 relevant = (handler->parentItem()->window() == win && epd.exclusiveGrabberContext.data() == q);
1463 devPriv->setExclusiveGrabber(
nullptr, epd.eventPoint,
nullptr);
1472void QQuickDeliveryAgentPrivate::handleWindowHidden(QQuickWindow *win)
1474 qCDebug(lcFocus) <<
"hidden" << win->title();
1476 lastMousePosition = QPointF();
1479bool QQuickDeliveryAgentPrivate::allUpdatedPointsAccepted(
const QPointerEvent *ev)
1481 for (
auto &point : ev->points()) {
1482 if (point.state() != QEventPoint::State::Pressed && !point.isAccepted())
1489
1490
1491
1492
1493
1494void QQuickDeliveryAgentPrivate::localizePointerEvent(QPointerEvent *ev,
const QQuickItem *dest)
1496 for (
int i = 0; i < ev->pointCount(); ++i) {
1497 auto &point = ev->point(i);
1498 QMutableEventPoint::setPosition(point, dest->mapFromScene(point.scenePosition()));
1499 qCDebug(lcPtrLoc) << ev->type() <<
"@" << point.scenePosition() <<
"to"
1500 << dest <<
"@" << dest->mapToScene(QPointF()) <<
"->" << point;
1504QList<QObject *> QQuickDeliveryAgentPrivate::exclusiveGrabbers(QPointerEvent *ev)
1506 QList<QObject *> result;
1507 for (
const QEventPoint &point : ev->points()) {
1508 if (QObject *grabber = ev->exclusiveGrabber(point)) {
1509 if (!result.contains(grabber))
1516bool QQuickDeliveryAgentPrivate::anyPointGrabbed(
const QPointerEvent *ev)
1518 for (
const QEventPoint &point : ev->points()) {
1519 if (ev->exclusiveGrabber(point) || !ev->passiveGrabbers(point).isEmpty())
1525bool QQuickDeliveryAgentPrivate::allPointsGrabbed(
const QPointerEvent *ev)
1527 for (
const auto &point : ev->points()) {
1528 if (!ev->exclusiveGrabber(point) && ev->passiveGrabbers(point).isEmpty())
1534bool QQuickDeliveryAgentPrivate::isMouseEvent(
const QPointerEvent *ev)
1536 switch (ev->type()) {
1537 case QEvent::MouseButtonPress:
1538 case QEvent::MouseButtonRelease:
1539 case QEvent::MouseButtonDblClick:
1540 case QEvent::MouseMove:
1547bool QQuickDeliveryAgentPrivate::isMouseOrWheelEvent(
const QPointerEvent *ev)
1549 return isMouseEvent(ev) || ev->type() == QEvent::Wheel;
1552bool QQuickDeliveryAgentPrivate::isHoverEvent(
const QPointerEvent *ev)
1554 switch (ev->type()) {
1555 case QEvent::HoverEnter:
1556 case QEvent::HoverMove:
1557 case QEvent::HoverLeave:
1564bool QQuickDeliveryAgentPrivate::isTouchEvent(
const QPointerEvent *ev)
1566 switch (ev->type()) {
1567 case QEvent::TouchBegin:
1568 case QEvent::TouchUpdate:
1569 case QEvent::TouchEnd:
1570 case QEvent::TouchCancel:
1577bool QQuickDeliveryAgentPrivate::isTabletEvent(
const QPointerEvent *ev)
1579#if QT_CONFIG(tabletevent)
1580 switch (ev->type()) {
1581 case QEvent::TabletPress:
1582 case QEvent::TabletMove:
1583 case QEvent::TabletRelease:
1584 case QEvent::TabletEnterProximity:
1585 case QEvent::TabletLeaveProximity:
1596bool QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(
const QPointerEvent *ev)
1598 const auto devType = ev->device()->type();
1599 return devType == QInputDevice::DeviceType::Mouse ||
1600 devType == QInputDevice::DeviceType::TouchPad;
1603bool QQuickDeliveryAgentPrivate::isSynthMouse(
const QPointerEvent *ev)
1605 return (!isEventFromMouseOrTouchpad(ev) && isMouseEvent(ev));
1609
1610
1611
1612bool QQuickDeliveryAgentPrivate::isSinglePointDevice(
const QInputDevice *dev)
1614 switch (dev->type()) {
1615 case QInputDevice::DeviceType::Mouse:
1616 case QInputDevice::DeviceType::TouchPad:
1617 case QInputDevice::DeviceType::Puck:
1618 case QInputDevice::DeviceType::Stylus:
1619 case QInputDevice::DeviceType::Airbrush:
1621 case QInputDevice::DeviceType::TouchScreen:
1622 case QInputDevice::DeviceType::Keyboard:
1623 case QInputDevice::DeviceType::Unknown:
1624 case QInputDevice::DeviceType::AllDevices:
1630QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(
const QInputDevice *device)
1632 QInputDevicePrivate *devPriv = QInputDevicePrivate::get(
const_cast<QInputDevice *>(device));
1633 if (devPriv->qqExtra)
1634 return static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1635 auto extra =
new QQuickPointingDeviceExtra;
1636 devPriv->qqExtra = extra;
1637 QObject::connect(device, &QObject::destroyed, [devPriv]() {
1638 delete static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1639 devPriv->qqExtra =
nullptr;
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
1672 if (isSubsceneAgent)
1675 QEventPoint::States states = event->touchPointStates();
1676 if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
1677 qCDebug(lcTouchCmprs) <<
"no compression" << event;
1682 if (!delayedTouch) {
1683 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points()));
1684 delayedTouch->setTimestamp(event->timestamp());
1685 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1686 auto &tp = delayedTouch->point(i);
1687 QMutableEventPoint::detach(tp);
1689 ++compressedTouchCount;
1690 qCDebug(lcTouchCmprs) <<
"delayed" << compressedTouchCount << delayedTouch.get();
1691 if (QQuickWindow *window = rootItem->window())
1692 window->maybeUpdate();
1697 if (delayedTouch->type() == event->type() &&
1698 delayedTouch->device() == event->device() &&
1699 delayedTouch->modifiers() == event->modifiers() &&
1700 delayedTouch->pointCount() == event->pointCount())
1703 bool mismatch =
false;
1705 auto tpts = event->points();
1706 for (qsizetype i = 0; i < event->pointCount(); ++i) {
1707 const auto &tp = tpts.at(i);
1708 const auto &tpDelayed = delayedTouch->point(i);
1709 if (tp.id() != tpDelayed.id()) {
1714 if (tpDelayed.state() == QEventPoint::State::Updated && tp.state() == QEventPoint::State::Stationary)
1715 QMutableEventPoint::setState(tpts[i], QEventPoint::State::Updated);
1722 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts));
1723 delayedTouch->setTimestamp(event->timestamp());
1724 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1725 auto &tp = delayedTouch->point(i);
1726 QMutableEventPoint::detach(tp);
1728 ++compressedTouchCount;
1729 qCDebug(lcTouchCmprs) <<
"coalesced" << compressedTouchCount << delayedTouch.get();
1730 if (QQuickWindow *window = rootItem->window())
1731 window->maybeUpdate();
1737 deliverDelayedTouchEvent();
1738 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(),
1739 event->modifiers(), event->points()));
1740 delayedTouch->setTimestamp(event->timestamp());
1748void QQuickDeliveryAgentPrivate::handleTouchEvent(QTouchEvent *event)
1750 Q_Q(QQuickDeliveryAgent);
1751 translateTouchEvent(event);
1753 if (event->pointCount()) {
1754 auto &point = event->point(0);
1755 if (point.state() == QEventPoint::State::Released) {
1756 lastMousePosition = QPointF();
1758 lastMousePosition = point.position();
1762 qCDebug(lcTouch) << q << event;
1764 static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet(
"QML_NO_TOUCH_COMPRESSION");
1766 if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) {
1767 deliverPointerEvent(event);
1771 if (!compressTouchEvent(event)) {
1773 deliverDelayedTouchEvent();
1774 qCDebug(lcTouchCmprs) <<
"resuming delivery" << event;
1776 deliverPointerEvent(event);
1781
1782
1783void QQuickDeliveryAgentPrivate::handleMouseEvent(QMouseEvent *event)
1785 Q_Q(QQuickDeliveryAgent);
1789 if (event->source() == Qt::MouseEventSynthesizedBySystem &&
1790 !(event->button() == Qt::RightButton && allowSyntheticRightClick())) {
1794 qCDebug(lcMouse) << q << event;
1796 switch (event->type()) {
1797 case QEvent::MouseButtonPress:
1798 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
1800 deliverPointerEvent(event);
1802 case QEvent::MouseButtonRelease:
1803 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
1805 deliverPointerEvent(event);
1806#if QT_CONFIG(cursor)
1807 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1810 case QEvent::MouseButtonDblClick:
1811 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1812 event->button(), event->buttons());
1813 deliverPointerEvent(event);
1815 case QEvent::MouseMove: {
1816 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
1817 event->position().x(), event->position().y());
1819 const QPointF last = lastMousePosition.isNull() ? event->scenePosition() : lastMousePosition;
1820 lastMousePosition = event->scenePosition();
1821 qCDebug(lcHoverTrace) << q << event <<
"mouse pos" << last <<
"->" << lastMousePosition;
1822 if (!event->points().size() || !event->exclusiveGrabber(event->point(0))) {
1823 bool accepted = deliverHoverEvent(event->scenePosition(), last, event->modifiers(), event->timestamp());
1824 event->setAccepted(accepted);
1826 deliverPointerEvent(event);
1827#if QT_CONFIG(cursor)
1829 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854void QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents(QQuickWindow *win)
1856 Q_Q(QQuickDeliveryAgent);
1857 QQuickDeliveryAgent *deliveringAgent = QQuickDeliveryAgentPrivate::currentEventDeliveryAgent;
1858 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = q;
1861 deliverDelayedTouchEvent();
1865 QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
1866 if (ut && ut->hasStartAnimationPending())
1867 ut->startAnimations();
1872#if !defined(Q_OS_WEBOS)
1882 if (frameSynchronousHoverInterval >= 0) {
1883 const bool timerActive = frameSynchronousHoverInterval > 0;
1884 const bool timerMature = frameSynchronousHoverTimer.elapsed() >= frameSynchronousHoverInterval;
1885 if (timerActive && !timerMature) {
1886 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery delayed: elapsed"
1887 << frameSynchronousHoverTimer.elapsed() <<
"<" << frameSynchronousHoverInterval;
1888 if (!frameSynchronousDelayTimer.isActive())
1889 frameSynchronousDelayTimer.start(frameSynchronousHoverInterval - frameSynchronousHoverTimer.elapsed(), q);
1890 }
else if (!win->mouseGrabberItem() && !lastMousePosition.isNull() &&
1891 (timerMature || QQuickWindowPrivate::get(win)->dirtyItemList)) {
1892 frameSynchronousDelayTimer.stop();
1893 qCDebug(lcHoverTrace) << q <<
"delivering frame-sync hover to root @" << lastMousePosition
1894 <<
"after elapsed time" << frameSynchronousHoverTimer.elapsed();
1895 if (deliverHoverEvent(lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0)) {
1896#if QT_CONFIG(cursor)
1897 QQuickWindowPrivate::get(rootItem->window())->updateCursor(
1898 sceneTransform ? sceneTransform->map(lastMousePosition) : lastMousePosition, rootItem);
1903 frameSynchronousHoverTimer.restart();
1904 ++frameSynchronousHover_counter;
1905 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery done: round" << frameSynchronousHover_counter;
1911 if (Q_UNLIKELY(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent &&
1912 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent != q))
1913 qCWarning(lcPtr,
"detected interleaved frame-sync and actual events");
1914 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveringAgent;
1918
1919
1920
1921
1922
1923
1924
1925void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition,
1926 const QPointerEvent *event,
const QEventPoint &point)
1928 Q_Q(QQuickDeliveryAgent);
1929 const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
1930 transition == QPointingDevice::GrabTransition::GrabPassive);
1933 if (
auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
1934 if (handler->parentItem()) {
1935 auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
1936 if (itemPriv->deliveryAgent() == q) {
1937 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1938 const_cast<QEventPoint &>(point));
1943 if (isSubsceneAgent && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
1944 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
1946 }
else if (!isSubsceneAgent) {
1947 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1948 const_cast<QEventPoint &>(point));
1950 }
else if (
auto *grabberItem = qmlobject_cast<QQuickItem *>(grabber)) {
1951 switch (transition) {
1952 case QPointingDevice::CancelGrabExclusive:
1953 case QPointingDevice::UngrabExclusive:
1954 if (isDeliveringTouchAsMouse() || isSinglePointDevice(point.device())) {
1957 QMutableSinglePointEvent e(QEvent::UngrabMouse, point.device(), point);
1958 hasFiltered.clear();
1959 if (!sendFilteredMouseEvent(&e, grabberItem, grabberItem->parentItem())) {
1960 lastUngrabbed = grabberItem;
1961 grabberItem->mouseUngrabEvent();
1966 bool allReleasedOrCancelled =
true;
1967 if (transition == QPointingDevice::UngrabExclusive && event) {
1968 for (
const auto &pt : event->points()) {
1969 if (pt.state() != QEventPoint::State::Released) {
1970 allReleasedOrCancelled =
false;
1975 if (allReleasedOrCancelled)
1976 grabberItem->touchUngrabEvent();
1982 auto *itemPriv = QQuickItemPrivate::get(grabberItem);
1985 if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
1986 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
1989 if (currentEventDeliveryAgent == q && event && event->device()) {
1990 switch (transition) {
1991 case QPointingDevice::GrabPassive: {
1992 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
1994 QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q);
1995 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
1997 case QPointingDevice::GrabExclusive: {
1998 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2000 epd->exclusiveGrabberContext = q;
2001 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2003 case QPointingDevice::CancelGrabExclusive:
2004 case QPointingDevice::UngrabExclusive:
2007 case QPointingDevice::UngrabPassive:
2008 case QPointingDevice::CancelGrabPassive:
2011 case QPointingDevice::OverrideGrabPassive:
2019
2020
2021
2022
2023
2024
2025
2026
2027void QQuickDeliveryAgentPrivate::ensureDeviceConnected(
const QPointingDevice *dev)
2029 Q_Q(QQuickDeliveryAgent);
2030 if (knownPointingDevices.contains(dev))
2032 knownPointingDevices.append(dev);
2033 connect(dev, &QPointingDevice::grabChanged,
this, &QQuickDeliveryAgentPrivate::onGrabChanged);
2034 QObject::connect(dev, &QObject::destroyed, q, [
this, dev] {
this->knownPointingDevices.removeAll(dev);});
2038
2039
2040
2041
2042
2043
2044void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
2046 Q_Q(QQuickDeliveryAgent);
2047 if (isTabletEvent(event))
2048 qCDebug(lcTablet) << q << event;
2053 ++pointerEventRecursionGuard;
2054 eventsInDelivery.push(event);
2060 QVarLengthArray<QPointF, 16> originalScenePositions;
2061 if (sceneTransform) {
2062 originalScenePositions.resize(event->pointCount());
2063 for (
int i = 0; i < event->pointCount(); ++i) {
2064 auto &pt = event->point(i);
2065 originalScenePositions[i] = pt.scenePosition();
2066 QMutableEventPoint::setScenePosition(pt, sceneTransform->map(pt.scenePosition()));
2067 qCDebug(lcPtrLoc) << q << event->type() << pt.id() <<
"transformed scene pos" << pt.scenePosition();
2069 }
else if (isSubsceneAgent) {
2070 qCDebug(lcPtrLoc) << q << event->type() <<
"no scene transform set";
2073 skipDelivery.clear();
2074 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
2076 qCDebug(lcPtr) << q <<
"delivering with" << sceneTransform << event;
2078 qCDebug(lcPtr) << q <<
"delivering" << event;
2079 for (
int i = 0; i < event->pointCount(); ++i)
2080 event->point(i).setAccepted(
false);
2082 if (event->isBeginEvent()) {
2083 ensureDeviceConnected(event->pointingDevice());
2084 if (event->type() == QEvent::MouseButtonPress && rootItem->window()
2085 &&
static_cast<QSinglePointEvent *>(event)->button() == Qt::RightButton) {
2086 QQuickWindowPrivate::get(rootItem->window())->rmbContextMenuEventEnabled =
true;
2088 if (!deliverPressOrReleaseEvent(event))
2089 event->setAccepted(
false);
2092 auto isHoveringMoveEvent = [](QPointerEvent *event) ->
bool {
2093 if (event->type() == QEvent::MouseMove) {
2094 const auto *spe =
static_cast<
const QSinglePointEvent *>(event);
2095 if (spe->button() == Qt::NoButton && spe->buttons() == Qt::NoButton)
2102
2103
2104
2105
2106
2107
2108
2109
2110 if (!allUpdatedPointsAccepted(event) && !isHoveringMoveEvent(event))
2111 deliverUpdatedPoints(event);
2112 if (event->isEndEvent())
2113 deliverPressOrReleaseEvent(event,
true);
2117 if (isTouchEvent(event) && touchMouseId >= 0) {
2118 if (
static_cast<QTouchEvent *>(event)->touchPointStates() == QEventPoint::State::Released) {
2119 cancelTouchMouseSynthesis();
2121 auto touchMousePoint = event->pointById(touchMouseId);
2122 if (touchMousePoint && touchMousePoint->state() == QEventPoint::State::Released)
2123 cancelTouchMouseSynthesis();
2127 eventsInDelivery.pop();
2128 if (sceneTransform) {
2129 for (
int i = 0; i < event->pointCount(); ++i)
2130 QMutableEventPoint::setScenePosition(event->point(i), originalScenePositions.at(i));
2132 --pointerEventRecursionGuard;
2133 lastUngrabbed =
nullptr;
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2174QList<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
const QEvent *event,
int pointId,
2175 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate)
const
2177 QList<QQuickItem *> targets;
2178 auto itemPrivate = QQuickItemPrivate::get(item);
2183 if (item != rootItem && !itemPrivate->eventHandlingBounds().contains(localPos) &&
2184 itemPrivate->effectivelyClipsEventHandlingChildren()) {
2185 qCDebug(lcPtrLoc) <<
"skipping because" << localPos <<
"is outside rectangular bounds of" << item;
2191 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2196 Q_ASSERT(event->isPointerEvent());
2197 QPointerEvent *pev =
const_cast<QPointerEvent *>(
static_cast<
const QPointerEvent *>(event));
2198 QEventPoint *point = pev->pointById(pointId);
2200 QMutableEventPoint::setPosition(*point, localPos);
2202 const std::optional<
bool> override = predicate(item, event);
2203 const bool relevant = override.has_value() ? override.value()
2204 : item == rootItem || item->contains(localPos);
2206 auto it = std::lower_bound(children.begin(), children.end(), 0,
2207 [](
auto lhs,
auto rhs) ->
bool {
return lhs->z() < rhs; });
2208 children.insert(it, item);
2213 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2214 QQuickItem *child = children.at(ii);
2215 auto childPrivate = QQuickItemPrivate::get(child);
2216 if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
2217 (child != item && childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
2220 if (child == item) {
2223 QTransform childToParent;
2224 childPrivate->itemToParentTransform(&childToParent);
2225 const QPointF childLocalPos = childToParent.inverted().map(localPos);
2226 targets << eventTargets(child, event, pointId, childLocalPos, scenePos, predicate);
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262QList<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *item,
const QPointerEvent *event,
const QEventPoint &point,
2263 bool checkMouseButtons,
bool checkAcceptsTouch)
const
2265 auto predicate = [point, checkMouseButtons, checkAcceptsTouch](QQuickItem *item,
const QEvent *ev) -> std::optional<
bool> {
2266 const QPointerEvent *event =
static_cast<
const QPointerEvent *>(ev);
2267 auto itemPrivate = QQuickItemPrivate::get(item);
2268 if (itemPrivate->hasPointerHandlers()) {
2269 if (itemPrivate->anyPointerHandlerWants(event, point))
2272 if (checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
2274 if (checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
2278 return std::nullopt;
2281 return eventTargets(item, event, point.id(), item->mapFromScene(point.scenePosition()), point.scenePosition(), predicate);
2285
2286
2287
2288QList<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(
const QList<QQuickItem *> &list1,
const QList<QQuickItem *> &list2)
const
2290 QList<QQuickItem *> targets = list1;
2294 int insertPosition = targets.size();
2295 for (
int i = list2.size() - 1; i >= 0; --i) {
2296 int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
2297 if (newInsertPosition >= 0) {
2298 Q_ASSERT(newInsertPosition <= insertPosition);
2299 insertPosition = newInsertPosition;
2302 if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
2303 targets.insert(insertPosition, list2.at(i));
2309
2310
2311void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
2313 Q_Q(
const QQuickDeliveryAgent);
2315 const auto grabbers = exclusiveGrabbers(event);
2316 hasFiltered.clear();
2317 for (
auto grabber : grabbers) {
2319 QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
2322 QQuickPointerHandler *handler =
static_cast<QQuickPointerHandler *>(grabber);
2323 receiver =
static_cast<QQuickPointerHandler *>(grabber)->parentItem();
2327 hasFiltered.clear();
2328 if (sendFilteredPointerEvent(event, receiver))
2330 localizePointerEvent(event, receiver);
2332 handler->handlePointerEvent(event);
2338 hasFiltered.clear();
2340 deliverMatchingPointsToItem(receiver,
true, event);
2344 for (
auto &point : event->points()) {
2345 auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
2346 if (Q_UNLIKELY(!epd)) {
2347 qWarning() <<
"point is not in activePoints" << point;
2350 QList<QPointer<QObject>> relevantPassiveGrabbers;
2351 for (
int i = 0; i < epd->passiveGrabbersContext.size(); ++i) {
2352 if (epd->passiveGrabbersContext.at(i).data() == q)
2353 relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
2355 if (!relevantPassiveGrabbers.isEmpty())
2356 deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
2359 if (event->type() == QEvent::TouchUpdate) {
2360 for (
const auto &[item, id] : hoverItems) {
2362 bool res = deliverHoverEventToItem(item, item->mapFromScene(point.scenePosition()), point.scenePosition(), point.sceneLastPosition(),
2363 point.globalPosition(), event->modifiers(), event->timestamp(), HoverChange::Set);
2365 Q_ASSERT(!res || hoverItems.value(item));
2375 if (!allPointsGrabbed(event)) {
2376 QList<QQuickItem *> targetItems;
2377 for (
auto &point : event->points()) {
2380 if (point.state() == QEventPoint::Pressed || qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(point)))
2382 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point,
false,
false);
2383 if (targetItems.size()) {
2384 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2386 targetItems = targetItemsForPoint;
2389 for (QQuickItem *item : targetItems) {
2390 if (grabbers.contains(item))
2392 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2393 localizePointerEvent(event, item);
2394 itemPrivate->handlePointerEvent(event,
true);
2395 if (allPointsGrabbed(event))
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event,
bool handlersOnly)
2442 QList<QQuickItem *> targetItems;
2443 const bool isTouch = isTouchEvent(event);
2444 if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) {
2445 if (
auto point =
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) {
2455 if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint)))
2456 cancelTouchMouseSynthesis();
2458 qCWarning(lcTouchTarget) <<
"during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId <<
"is missing from" << event;
2461 for (
int i = 0; i < event->pointCount(); ++i) {
2462 auto &point = event->point(i);
2466 if (isTouch && point.state() == QEventPoint::Pressed)
2467 resetIfDoubleTapPrevented(point);
2468 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch);
2469 if (targetItems.size()) {
2470 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2472 targetItems = targetItemsForPoint;
2476 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
2478 for (
auto &item : safeTargetItems) {
2482 if (isSubsceneAgent)
2483 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
2485 hasFiltered.clear();
2486 if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
2487 if (event->isAccepted())
2489 skipDelivery.append(item);
2494 if (skipDelivery.contains(item))
2499 for (
int i = 0; i < event->pointCount(); ++i)
2500 event->point(i).setAccepted(
false);
2502 deliverMatchingPointsToItem(item,
false, event, handlersOnly);
2503 if (event->allPointsAccepted())
2504 handlersOnly =
true;
2510 return handlersOnly;
2514
2515
2516
2517
2518
2519
2520
2521void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item,
bool isGrabber, QPointerEvent *pointerEvent,
bool handlersOnly)
2523 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2524#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
2529 if (itemPrivate->wasDeleted)
2532 localizePointerEvent(pointerEvent, item);
2533 bool isMouse = isMouseEvent(pointerEvent);
2537 if (pointerEvent->type() != QEvent::MouseButtonDblClick)
2538 itemPrivate->handlePointerEvent(pointerEvent);
2545 if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent()
2546 && !exclusiveGrabbers(pointerEvent).contains(item))
2550 if (sendFilteredPointerEvent(pointerEvent, item))
2556 auto button =
static_cast<QSinglePointEvent *>(pointerEvent)->button();
2557 if ((isGrabber && button == Qt::NoButton) || item->acceptedMouseButtons().testFlag(button)) {
2560 auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0));
2561 pointerEvent->accept();
2562 if (isGrabber && sendFilteredPointerEvent(pointerEvent, item))
2564 localizePointerEvent(pointerEvent, item);
2565 QCoreApplication::sendEvent(item, pointerEvent);
2566 if (pointerEvent->isAccepted()) {
2567 auto &point = pointerEvent->point(0);
2568 auto mouseGrabber = pointerEvent->exclusiveGrabber(point);
2569 if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
2575 if (item != lastUngrabbed) {
2576 item->mouseUngrabEvent();
2577 lastUngrabbed = item;
2579 }
else if (item->isEnabled() && item->isVisible() && point.state() == QEventPoint::State::Pressed) {
2580 pointerEvent->setExclusiveGrabber(point, item);
2582 point.setAccepted(
true);
2588 if (!isTouchEvent(pointerEvent))
2591 bool eventAccepted =
false;
2592 QMutableTouchEvent touchEvent;
2593 itemPrivate->localizedTouchEvent(
static_cast<QTouchEvent *>(pointerEvent),
false, &touchEvent);
2594 if (touchEvent.type() == QEvent::None)
2597 if (item->acceptTouchEvents()) {
2598 qCDebug(lcTouch) <<
"considering delivering" << &touchEvent <<
" to " << item;
2601 qCDebug(lcTouch) <<
"actually delivering" << &touchEvent <<
" to " << item;
2602 QCoreApplication::sendEvent(item, &touchEvent);
2603 eventAccepted = touchEvent.isAccepted();
2606 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2607 !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
2608 deliverTouchAsMouse(item, &touchEvent);
2612 Q_ASSERT(item->acceptTouchEvents());
2613 if (eventAccepted) {
2614 bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
2615 for (
int i = 0; i < touchEvent.pointCount(); ++i) {
2616 auto &point = touchEvent.point(i);
2618 point.setAccepted();
2620 if (isPressOrRelease && !(itemPrivate->deliveryAgent() && pointerEvent->exclusiveGrabber(point)))
2621 pointerEvent->setExclusiveGrabber(point, item);
2626 for (
const auto &point: touchEvent.points()) {
2627 if (point.state() == QEventPoint::State::Pressed) {
2628 if (pointerEvent->exclusiveGrabber(point) == item) {
2629 qCDebug(lcTouchTarget) <<
"TP" << Qt::hex << point.id() <<
"disassociated";
2630 pointerEvent->setExclusiveGrabber(point,
nullptr);
2637#if QT_CONFIG(quick_draganddrop)
2638void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
2640 QObject *formerTarget = grabber->target();
2641 grabber->resetTarget();
2642 QQuickDragGrabber::iterator grabItem = grabber->begin();
2643 if (grabItem != grabber->end()) {
2644 Q_ASSERT(event->type() != QEvent::DragEnter);
2645 if (event->type() == QEvent::Drop) {
2646 QDropEvent *e =
static_cast<QDropEvent *>(event);
2647 for (e->setAccepted(
false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
2648 QPointF p = (**grabItem)->mapFromScene(e->position().toPoint());
2649 QDropEvent translatedEvent(
2651 e->possibleActions(),
2655 QQuickDropEventEx::copyActions(&translatedEvent, *e);
2656 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2657 e->setAccepted(translatedEvent.isAccepted());
2658 e->setDropAction(translatedEvent.dropAction());
2659 grabber->setTarget(**grabItem);
2662 if (event->type() != QEvent::DragMove) {
2663 QDragLeaveEvent leaveEvent;
2664 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2665 QCoreApplication::sendEvent(**grabItem, &leaveEvent);
2666 grabber->ignoreList().clear();
2669 QDragMoveEvent *moveEvent =
static_cast<QDragMoveEvent *>(event);
2673 QVarLengthArray<QQuickItem*, 64> currentGrabItems;
2674 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2675 currentGrabItems.append(**grabItem);
2678 QDragEnterEvent enterEvent(
2679 moveEvent->position().toPoint(),
2680 moveEvent->possibleActions(),
2681 moveEvent->mimeData(),
2682 moveEvent->buttons(),
2683 moveEvent->modifiers());
2684 QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
2685 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, ¤tGrabItems,
2688 for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
2689 int i = currentGrabItems.indexOf(**grabItem);
2691 currentGrabItems.remove(i);
2693 QDragMoveEvent translatedEvent(
2694 (**grabItem)->mapFromScene(moveEvent->position().toPoint()).toPoint(),
2695 moveEvent->possibleActions(),
2696 moveEvent->mimeData(),
2697 moveEvent->buttons(),
2698 moveEvent->modifiers());
2699 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
2700 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2701 event->setAccepted(translatedEvent.isAccepted());
2702 QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
2707 QDragLeaveEvent leaveEvent;
2708 for (QQuickItem *i : currentGrabItems)
2709 QCoreApplication::sendEvent(i, &leaveEvent);
2714 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
2715 QDragMoveEvent *e =
static_cast<QDragMoveEvent *>(event);
2716 QDragEnterEvent enterEvent(
2717 e->position().toPoint(),
2718 e->possibleActions(),
2722 QQuickDropEventEx::copyActions(&enterEvent, *e);
2723 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
2725 grabber->ignoreList().clear();
2729bool QQuickDeliveryAgentPrivate::deliverDragEvent(
2730 QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
2731 QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
2733 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2734 if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
2736 QPointF p = item->mapFromScene(event->position().toPoint());
2737 bool itemContained = item->contains(p);
2739 const int itemIndex = grabber->ignoreList().indexOf(item);
2740 if (!itemContained) {
2742 grabber->ignoreList().remove(itemIndex);
2744 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
2748 QDragEnterEvent enterEvent(
2749 event->position().toPoint(),
2750 event->possibleActions(),
2753 event->modifiers());
2754 QQuickDropEventEx::copyActions(&enterEvent, *event);
2755 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2758 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2759 if (children.at(ii)->z() < 0)
2761 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2765 if (itemContained) {
2768 if (currentGrabItems && currentGrabItems->contains(item)) {
2769 grabber->grab(item);
2770 grabber->setTarget(item);
2774 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
2775 if (event->type() == QEvent::DragEnter) {
2777 QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
2778 if (formerTargetItem && currentGrabItems) {
2779 QDragLeaveEvent leaveEvent;
2780 QCoreApplication::sendEvent(formerTarget, &leaveEvent);
2784 currentGrabItems->removeAll(formerTarget);
2786 }
else if (itemIndex >= 0) {
2791 QDragMoveEvent translatedEvent(p.toPoint(), event->possibleActions(), event->mimeData(),
2792 event->buttons(), event->modifiers(), event->type());
2793 QQuickDropEventEx::copyActions(&translatedEvent, *event);
2794 translatedEvent.setAccepted(event->isAccepted());
2795 QCoreApplication::sendEvent(item, &translatedEvent);
2796 event->setAccepted(translatedEvent.isAccepted());
2797 event->setDropAction(translatedEvent.dropAction());
2798 if (event->type() == QEvent::DragEnter) {
2799 if (translatedEvent.isAccepted()) {
2800 grabber->grab(item);
2801 grabber->setTarget(item);
2803 }
else if (itemIndex < 0) {
2804 grabber->ignoreList().append(item);
2813 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2814 if (children.at(ii)->z() >= 0)
2816 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2825
2826
2827
2828
2829
2830
2831
2832bool QQuickDeliveryAgentPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2834 return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
2838
2839
2840bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2842 if (!allowChildEventFiltering)
2844 if (!filteringParent)
2846 bool filtered =
false;
2847 const bool hasHandlers = QQuickItemPrivate::get(receiver)->hasPointerHandlers();
2848 if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
2849 hasFiltered.append(filteringParent);
2850 if (isMouseEvent(event)) {
2851 if (receiver->acceptedMouseButtons()) {
2852 const bool wasAccepted = event->allPointsAccepted();
2853 Q_ASSERT(event->pointCount());
2854 localizePointerEvent(event, receiver);
2855 event->setAccepted(
true);
2856 auto oldMouseGrabber = event->exclusiveGrabber(event->point(0));
2857 if (filteringParent->childMouseEventFilter(receiver, event)) {
2858 qCDebug(lcMouse) <<
"mouse event intercepted by childMouseEventFilter of " << filteringParent;
2859 skipDelivery.append(filteringParent);
2861 if (event->isAccepted() && event->isBeginEvent()) {
2862 auto &point = event->point(0);
2863 auto mouseGrabber = event->exclusiveGrabber(point);
2864 if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
2865 receiver->mouseUngrabEvent();
2867 event->setExclusiveGrabber(point, receiver);
2872 event->setAccepted(wasAccepted);
2875 }
else if (isTouchEvent(event)) {
2876 const bool acceptsTouchEvents = receiver->acceptTouchEvents() || hasHandlers;
2877 auto device = event->device();
2878 if (device->type() == QInputDevice::DeviceType::TouchPad &&
2879 device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
2880 qCDebug(lcTouchTarget) <<
"skipping filtering of synth-mouse event from" << device;
2881 }
else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
2884 QMutableTouchEvent filteringParentTouchEvent;
2885 QQuickItemPrivate::get(receiver)->localizedTouchEvent(
static_cast<QTouchEvent *>(event),
true, &filteringParentTouchEvent);
2886 if (filteringParentTouchEvent.type() != QEvent::None) {
2887 qCDebug(lcTouch) <<
"letting parent" << filteringParent <<
"filter for" << receiver << &filteringParentTouchEvent;
2888 filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent);
2890 qCDebug(lcTouch) <<
"touch event intercepted by childMouseEventFilter of " << filteringParent;
2891 event->setAccepted(filteringParentTouchEvent.isAccepted());
2892 skipDelivery.append(filteringParent);
2893 if (event->isAccepted()) {
2894 for (
auto point : filteringParentTouchEvent.points()) {
2895 const QQuickItem *exclusiveGrabber = qobject_cast<
const QQuickItem *>(event->exclusiveGrabber(point));
2896 if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab())
2897 event->setExclusiveGrabber(point, filteringParent);
2900 }
else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2901 !filteringParent->acceptTouchEvents()) {
2902 qCDebug(lcTouch) <<
"touch event NOT intercepted by childMouseEventFilter of " << filteringParent
2903 <<
"; accepts touch?" << filteringParent->acceptTouchEvents()
2904 <<
"receiver accepts touch?" << acceptsTouchEvents
2905 <<
"so, letting parent filter a synth-mouse event";
2907 for (
auto &tp : filteringParentTouchEvent.points()) {
2909 switch (tp.state()) {
2910 case QEventPoint::State::Pressed:
2911 t = QEvent::MouseButtonPress;
2913 case QEventPoint::State::Released:
2914 t = QEvent::MouseButtonRelease;
2916 case QEventPoint::State::Stationary:
2919 t = QEvent::MouseMove;
2923 bool touchMouseUnset = (touchMouseId == -1);
2925 if (touchMouseUnset || touchMouseId == tp.id()) {
2928 QMutableSinglePointEvent mouseEvent;
2929 touchToMouseEvent(t, tp, &filteringParentTouchEvent, &mouseEvent);
2933 touchMouseId = tp.id();
2934 touchMouseDevice = event->pointingDevice();
2935 filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent);
2937 qCDebug(lcTouch) <<
"touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
2938 event->setAccepted(mouseEvent.isAccepted());
2939 skipDelivery.append(filteringParent);
2940 if (event->isAccepted() && event->isBeginEvent()) {
2941 qCDebug(lcTouchTarget) <<
"TP (mouse)" << Qt::hex << tp.id() <<
"->" << filteringParent;
2942 filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent);
2943 touchMouseUnset =
false;
2944 filteringParent->grabMouse();
2947 if (touchMouseUnset)
2950 cancelTouchMouseSynthesis();
2951 mouseEvent.point(0).setAccepted(
false);
2962 return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976bool QQuickDeliveryAgentPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2978 if (!filteringParent)
2981 QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
2982 if (filteringParentPrivate->replayingPressEvent)
2985 bool filtered =
false;
2986 if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
2987 hasFiltered.append(filteringParent);
2988 if (filteringParent->childMouseEventFilter(receiver, event)) {
2990 skipDelivery.append(filteringParent);
2992 qCDebug(lcMouseTarget) <<
"for" << receiver << filteringParent <<
"childMouseEventFilter ->" << filtered;
2995 return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
2999
3000
3001
3002
3003
3004
3005bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event,
int startDragThreshold)
3007 QStyleHints *styleHints = QGuiApplication::styleHints();
3008 bool dragVelocityLimitAvailable = event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
3009 && styleHints->startDragVelocity();
3010 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3011 if (dragVelocityLimitAvailable) {
3012 QVector2D velocityVec = event->point(0).velocity();
3013 qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
3014 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3016 return overThreshold;
3020
3021
3022
3023
3024
3025
3026bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const QEventPoint &tp,
int startDragThreshold)
3028 QStyleHints *styleHints = qApp->styleHints();
3029 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3030 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
3031 if (!overThreshold && dragVelocityLimitAvailable) {
3032 qreal velocity = axis == Qt::XAxis ? tp.velocity().x() : tp.velocity().y();
3033 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3035 return overThreshold;
3039
3040
3041
3042
3043bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
3045 int threshold = qApp->styleHints()->startDragDistance();
3046 return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
3050
3051
3052
3053
3054
3055
3056QList<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item,
const QContextMenuEvent *event)
const
3058 auto predicate = [](QQuickItem *,
const QEvent *) -> std::optional<
bool> {
3059 return std::nullopt;
3062 const auto pos = event->pos().isNull() ? activeFocusItem->mapToScene({}).toPoint() : event->pos();
3063 if (event->pos().isNull())
3064 qCDebug(lcContextMenu) <<
"for QContextMenuEvent, active focus item is" << activeFocusItem <<
"@" << pos;
3065 return eventTargets(item, event, -1, pos, pos, predicate);
3069
3070
3071
3072
3073void QQuickDeliveryAgentPrivate::deliverContextMenuEvent(QContextMenuEvent *event)
3075 skipDelivery.clear();
3076 QList<QQuickItem *> targetItems = contextMenuTargets(rootItem, event);
3077 qCDebug(lcContextMenu) <<
"delivering context menu event" << event <<
"to" << targetItems.size() <<
"target item(s)";
3078 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
3079 for (
auto &item : safeTargetItems) {
3080 qCDebug(lcContextMenu) <<
"- attempting to deliver to" << item;
3084 if (isSubsceneAgent)
3085 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
3087 QCoreApplication::sendEvent(item, event);
3088 if (event->isAccepted())
3093#ifndef QT_NO_DEBUG_STREAM
3096 QDebugStateSaver saver(debug);
3099 debug <<
"QQuickDeliveryAgent(0)";
3103 debug <<
"QQuickDeliveryAgent(";
3104 if (!da->objectName().isEmpty())
3105 debug << da->objectName() <<
' ';
3106 auto root = da->rootItem();
3107 if (Q_LIKELY(root)) {
3108 debug <<
"root=" << root->metaObject()->className();
3109 if (!root->objectName().isEmpty())
3110 debug <<
' ' << root->objectName();
3121#include "moc_qquickdeliveryagent_p.cpp"
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static bool allowSyntheticRightClick()
static bool windowHasFocus(QQuickWindow *win)
static QQuickItem * findFurthestFocusScopeAncestor(QQuickItem *item)