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>
23#include <QtCore/qvarlengtharray.h>
31Q_STATIC_LOGGING_CATEGORY(lcTouchCmprs,
"qt.quick.touch.compression")
32Q_LOGGING_CATEGORY(lcTouchTarget,
"qt.quick.touch.target")
33Q_LOGGING_CATEGORY(lcMouse,
"qt.quick.mouse")
34Q_STATIC_LOGGING_CATEGORY(lcMouseTarget,
"qt.quick.mouse.target")
35Q_STATIC_LOGGING_CATEGORY(lcTablet,
"qt.quick.tablet")
36Q_LOGGING_CATEGORY(lcPtr,
"qt.quick.pointer")
37Q_STATIC_LOGGING_CATEGORY(lcPtrLoc,
"qt.quick.pointer.localization")
38Q_STATIC_LOGGING_CATEGORY(lcWheelTarget,
"qt.quick.wheel.target")
39Q_LOGGING_CATEGORY(lcHoverTrace,
"qt.quick.hover.trace")
40Q_LOGGING_CATEGORY(lcHoverCursor,
"qt.quick.hover.cursor")
41Q_LOGGING_CATEGORY(lcFocus,
"qt.quick.focus")
42Q_STATIC_LOGGING_CATEGORY(lcContextMenu,
"qt.quick.contextmenu")
46bool QQuickDeliveryAgentPrivate::subsceneAgentsExist(
false);
47QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentEventDeliveryAgent(
nullptr);
51 static int allowRightClick = -1;
52 if (allowRightClick < 0) {
54 allowRightClick = qEnvironmentVariableIntValue(
"QT_QUICK_ALLOW_SYNTHETIC_RIGHT_CLICK", &ok);
58 return allowRightClick != 0;
63 return std::find_if(hoverItems.begin(), hoverItems.end(),
64 [item](
const QQuickDeliveryAgentPrivate::HoverItemState &hoverState) {
65 return hoverState.item == item;
71 return std::find_if(hoverItems.cbegin(), hoverItems.cend(),
72 [item](
const QQuickDeliveryAgentPrivate::HoverItemState &hoverState) {
73 return hoverState.item == item;
78
79
80
81
82
83
84
85
86
87
88static void markHovered(QQuickDeliveryAgentPrivate::HoverItemState &state, uint hoverId,
bool fromTouch)
90 if (state.hoverId == 0)
91 state.fromTouch = fromTouch;
92 state.hoverId = hoverId;
95void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type,
const QEventPoint &p,
const QTouchEvent *touchEvent, QMutableSinglePointEvent *mouseEvent)
97 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
98 QMutableSinglePointEvent ret(type, touchEvent->pointingDevice(), p,
99 (type == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton),
100 (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton),
101 touchEvent->modifiers(), Qt::MouseEventSynthesizedByQt);
102 ret.setAccepted(
true);
103 ret.setTimestamp(touchEvent->timestamp());
107 Q_ASSERT(mouseEvent->device() == touchEvent->device());
108 if (Q_UNLIKELY(mouseEvent->device()->type() == QInputDevice::DeviceType::Mouse))
109 qWarning() <<
"Unexpected: synthesized an indistinguishable mouse event" << mouseEvent;
113
114
115bool QQuickDeliveryAgentPrivate::isWithinDoubleClickInterval(ulong timeInterval)
117 return timeInterval <
static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
121
122
123bool QQuickDeliveryAgentPrivate::isWithinDoubleTapDistance(
const QPoint &distanceBetweenPresses)
125 auto square = [](qint64 v) {
return v * v; };
126 return square(distanceBetweenPresses.x()) + square(distanceBetweenPresses.y()) <
127 square(QGuiApplication::styleHints()->touchDoubleTapDistance());
130bool QQuickDeliveryAgentPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp,
const QPoint &newPressPos)
132 const bool doubleClicked = isDeliveringTouchAsMouse() &&
133 isWithinDoubleTapDistance(newPressPos - touchMousePressPos) &&
134 isWithinDoubleClickInterval(newPressEventTimestamp - touchMousePressTimestamp);
136 touchMousePressTimestamp = 0;
138 touchMousePressTimestamp = newPressEventTimestamp;
139 touchMousePressPos = newPressPos;
141 return doubleClicked;
144void QQuickDeliveryAgentPrivate::resetIfDoubleTapPrevented(
const QEventPoint &pressedPoint)
146 if (touchMousePressTimestamp > 0 &&
147 (!isWithinDoubleTapDistance(pressedPoint.globalPosition().toPoint() - touchMousePressPos) ||
148 !isWithinDoubleClickInterval(pressedPoint.timestamp() - touchMousePressTimestamp))) {
149 touchMousePressTimestamp = 0;
150 touchMousePressPos = QPoint();
155
156
157
158
159
160
161
162QPointerEvent *QQuickDeliveryAgentPrivate::eventInDelivery()
const
164 if (eventsInDelivery.isEmpty())
166 return eventsInDelivery.top();
170
171
172
173
174
175QPointingDevicePrivate::EventPointData *QQuickDeliveryAgentPrivate::mousePointData()
177 if (eventsInDelivery.isEmpty())
179 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(eventsInDelivery.top()->pointingDevice()));
180 return devPriv->queryPointById(isDeliveringTouchAsMouse() ? touchMouseId : 0);
183void QQuickDeliveryAgentPrivate::cancelTouchMouseSynthesis()
185 qCDebug(lcTouchTarget) <<
"id" << touchMouseId <<
"on" << touchMouseDevice;
187 touchMouseDevice =
nullptr;
190bool QQuickDeliveryAgentPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent)
192 Q_Q(QQuickDeliveryAgent);
193 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
194 auto device = pointerEvent->pointingDevice();
197 if (isTouchPadWithMouseEmulation(pointerEvent->device())) {
198 qCDebug(lcTouchTarget) << q <<
"skipping delivery of synth-mouse event from" << device;
203 QMutableTouchEvent event;
204 QQuickItemPrivate::get(item)->localizedTouchEvent(pointerEvent,
false, &event);
205 if (!event.points().size())
211 for (
auto &p : event.points()) {
213 if (touchMouseId == -1 && p.state() & QEventPoint::State::Pressed) {
214 QPointF pos = item->mapFromScene(p.scenePosition());
217 if (!item->contains(pos))
220 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << item;
221 QMutableSinglePointEvent mousePress;
222 touchToMouseEvent(QEvent::MouseButtonPress, p, &event, &mousePress);
225 QCoreApplication::sendEvent(item, &mousePress);
226 event.setAccepted(mousePress.isAccepted());
227 if (mousePress.isAccepted()) {
228 touchMouseDevice = device;
229 touchMouseId = p.id();
230 const auto &pt = mousePress.point(0);
231 if (!mousePress.exclusiveGrabber(pt))
232 mousePress.setExclusiveGrabber(pt, item);
234 if (checkIfDoubleTapped(event.timestamp(), p.globalPosition().toPoint())) {
237 QMutableSinglePointEvent mouseDoubleClick;
238 touchToMouseEvent(QEvent::MouseButtonDblClick, p, &event, &mouseDoubleClick);
239 QCoreApplication::sendEvent(item, &mouseDoubleClick);
240 event.setAccepted(mouseDoubleClick.isAccepted());
241 if (!mouseDoubleClick.isAccepted())
242 cancelTouchMouseSynthesis();
250 }
else if (touchMouseDevice == device && p.id() == touchMouseId) {
251 if (p.state() & QEventPoint::State::Updated) {
252 if (touchMousePressTimestamp != 0) {
253 if (!isWithinDoubleTapDistance(p.globalPosition().toPoint() - touchMousePressPos))
254 touchMousePressTimestamp = 0;
256 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
257 QMutableSinglePointEvent me;
258 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
259 QCoreApplication::sendEvent(item, &me);
260 event.setAccepted(me.isAccepted());
262 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << mouseGrabberItem;
263 return event.isAccepted();
268 QMutableSinglePointEvent me;
269 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
270 if (lastMousePosition.isNull())
271 lastMousePosition = me.scenePosition();
272 QPointF last = lastMousePosition;
273 lastMousePosition = me.scenePosition();
275 deliverHoverEvent(me.scenePosition(), last, me.modifiers(), me.timestamp());
278 }
else if (p.state() & QEventPoint::State::Released) {
280 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
281 QMutableSinglePointEvent me;
282 touchToMouseEvent(QEvent::MouseButtonRelease, p, &event, &me);
283 QCoreApplication::sendEvent(item, &me);
285 if (pointerEvent->exclusiveGrabber(p) == mouseGrabberItem)
286 pointerEvent->setExclusiveGrabber(p,
nullptr);
288 cancelTouchMouseSynthesis();
289 return me.isAccepted();
299
300
301
302
303
304
305
306
307void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber,
bool mouse,
bool touch,
bool cancel)
309 Q_Q(QQuickDeliveryAgent);
310 if (eventsInDelivery.isEmpty()) {
312 for (
auto dev : knownPointingDevices) {
313 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(dev));
314 devPriv->removeGrabber(grabber, cancel);
318 auto eventInDelivery = eventsInDelivery.top();
319 if (Q_LIKELY(mouse) && eventInDelivery) {
320 auto epd = mousePointData();
321 if (epd && epd->exclusiveGrabber == grabber && epd->exclusiveGrabberContext.data() == q) {
322 QQuickItem *oldGrabber = qobject_cast<QQuickItem *>(epd->exclusiveGrabber);
323 qCDebug(lcMouseTarget) <<
"removeGrabber" << oldGrabber <<
"-> null";
324 eventInDelivery->setExclusiveGrabber(epd->eventPoint,
nullptr);
327 if (Q_LIKELY(touch)) {
329 const auto touchDevices = QPointingDevice::devices();
330 for (
auto device : touchDevices) {
331 if (device->type() != QInputDevice::DeviceType::TouchScreen)
333 if (QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(
static_cast<
const QPointingDevice *>(device)))->
334 removeExclusiveGrabber(eventInDelivery, grabber))
338 grabber->touchUngrabEvent();
343
344
345
346
347
348
349
350
351
352
353
354void QQuickDeliveryAgentPrivate::clearGrabbers(QPointerEvent *pointerEvent)
356 if (pointerEvent->isEndEvent()
357 && !(isTabletEvent(pointerEvent)
358 && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
359 || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
360 if (pointerEvent->isSinglePointEvent()) {
361 if (
static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
362 auto &firstPt = pointerEvent->point(0);
363 pointerEvent->setExclusiveGrabber(firstPt,
nullptr);
364 pointerEvent->clearPassiveGrabbers(firstPt);
367 for (
auto &point : pointerEvent->points()) {
368 if (point.state() == QEventPoint::State::Released) {
369 pointerEvent->setExclusiveGrabber(point,
nullptr);
370 pointerEvent->clearPassiveGrabbers(point);
378
379
380
381
382void QQuickDeliveryAgentPrivate::translateTouchEvent(QTouchEvent *touchEvent)
384 for (qsizetype i = 0; i != touchEvent->pointCount(); ++i) {
385 auto &pt = touchEvent->point(i);
386 QMutableEventPoint::setScenePosition(pt, pt.position());
393 const QWindow *focusWindow = QGuiApplication::focusWindow();
394 if (!focusWindow || win == focusWindow)
396 return QQuickRenderControlPrivate::isFocusWindowFor(win, focusWindow);
401 QQuickItem *parentItem = item->parentItem();
403 if (parentItem && parentItem->flags() & QQuickItem::ItemIsFocusScope)
404 return findFurthestFocusScopeAncestor(parentItem);
411static inline bool singleWindowOnScreen(QQuickWindow *win)
413 const QWindowList windowList = QGuiApplication::allWindows();
414 for (
int i = 0; i < windowList.count(); i++) {
415 QWindow *ii = windowList.at(i);
418 if (ii->screen() == win->screen())
427
428
429
430
431void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item,
432 Qt::FocusReason reason, FocusOptions options)
434 Q_Q(QQuickDeliveryAgent);
436 Q_ASSERT(scope || item == rootItem);
438 qCDebug(lcFocus) << q <<
"focus" << item <<
"in scope" << scope;
440 qCDebug(lcFocus) <<
" scopeSubFocusItem:" << QQuickItemPrivate::get(scope)->subFocusItem;
442 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) :
nullptr;
443 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
445 QQuickItem *oldActiveFocusItem =
nullptr;
446 QQuickItem *currentActiveFocusItem = activeFocusItem;
447 QQuickItem *newActiveFocusItem =
nullptr;
448 bool sendFocusIn =
false;
450 lastFocusReason = reason;
452 QVarLengthArray<QQuickItem *, 20> changed;
455 if (item == rootItem || scopePrivate->activeFocus) {
456 oldActiveFocusItem = activeFocusItem;
457 if (item->isEnabled()) {
458 newActiveFocusItem = item;
459 while (newActiveFocusItem->isFocusScope()
460 && newActiveFocusItem->scopedFocusItem()
461 && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
462 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
465 newActiveFocusItem = scope;
468 if (oldActiveFocusItem) {
470 QGuiApplication::inputMethod()->commit();
473 activeFocusItem =
nullptr;
475 QQuickItem *afi = oldActiveFocusItem;
476 while (afi && afi != scope) {
477 if (QQuickItemPrivate::get(afi)->activeFocus) {
478 QQuickItemPrivate::get(afi)->activeFocus =
false;
481 afi = afi->parentItem();
486 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
487 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
488 if (oldSubFocusItem) {
489 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
491 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
492 changed << oldSubFocusItem;
495 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
true);
498 if (!(options & DontChangeFocusProperty)) {
499 if (item != rootItem || windowHasFocus(rootItem->window())
503 || singleWindowOnScreen(rootItem->window())
506 itemPrivate->focus =
true;
507 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
512 if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) {
513 activeFocusItem = newActiveFocusItem;
515 QQuickItemPrivate::get(newActiveFocusItem)->activeFocus =
true;
516 changed << newActiveFocusItem;
518 QQuickItem *afi = newActiveFocusItem->parentItem();
519 while (afi && afi != scope) {
520 if (afi->isFocusScope()) {
521 QQuickItemPrivate::get(afi)->activeFocus =
true;
524 afi = afi->parentItem();
526 updateFocusItemTransform();
532 if (oldActiveFocusItem) {
533 QFocusEvent event(QEvent::FocusOut, reason);
534 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
538 if (sendFocusIn && activeFocusItem == newActiveFocusItem) {
539 QFocusEvent event(QEvent::FocusIn, reason);
540 QCoreApplication::sendEvent(newActiveFocusItem, &event);
543 if (activeFocusItem != currentActiveFocusItem)
544 emit rootItem->window()->focusObjectChanged(activeFocusItem);
546 if (!changed.isEmpty())
547 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
548 if (isSubsceneAgent) {
549 auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent;
550 qCDebug(lcFocus) <<
" delegating setFocusInScope to" << da;
558 QQuickItem *ancestorFS = findFurthestFocusScopeAncestor(item);
559 if (ancestorFS != item)
560 options |= QQuickDeliveryAgentPrivate::DontChangeSubFocusItem;
561 QQuickWindowPrivate::get(rootItem->window())->deliveryAgentPrivate()->setFocusInScope(da->rootItem(), item, reason, options);
563 if (oldActiveFocusItem == activeFocusItem)
564 qCDebug(lcFocus) <<
" activeFocusItem remains" << activeFocusItem <<
"in" << q;
566 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
569void QQuickDeliveryAgentPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions options)
572 Q_ASSERT(scope || item == rootItem);
573 Q_Q(QQuickDeliveryAgent);
574 qCDebug(lcFocus) << q <<
"clear focus" << item <<
"in scope" << scope;
576 QQuickItemPrivate *scopePrivate =
nullptr;
578 scopePrivate = QQuickItemPrivate::get(scope);
579 if ( !scopePrivate->subFocusItem )
583 QQuickItem *currentActiveFocusItem = activeFocusItem;
584 QQuickItem *oldActiveFocusItem =
nullptr;
585 QQuickItem *newActiveFocusItem =
nullptr;
587 lastFocusReason = reason;
589 QVarLengthArray<QQuickItem *, 20> changed;
591 Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
594 if (item == rootItem || scopePrivate->activeFocus) {
595 oldActiveFocusItem = activeFocusItem;
596 newActiveFocusItem = scope;
599 QGuiApplication::inputMethod()->commit();
602 activeFocusItem =
nullptr;
604 if (oldActiveFocusItem) {
605 QQuickItem *afi = oldActiveFocusItem;
606 while (afi && afi != scope) {
607 if (QQuickItemPrivate::get(afi)->activeFocus) {
608 QQuickItemPrivate::get(afi)->activeFocus =
false;
611 afi = afi->parentItem();
616 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
617 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
618 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
619 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
621 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
622 changed << oldSubFocusItem;
625 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
false);
627 }
else if (!(options & DontChangeFocusProperty)) {
628 QQuickItemPrivate *priv = QQuickItemPrivate::get(item);
630 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
634 if (newActiveFocusItem) {
635 Q_ASSERT(newActiveFocusItem == scope);
636 activeFocusItem = scope;
637 updateFocusItemTransform();
642 if (oldActiveFocusItem) {
643 QFocusEvent event(QEvent::FocusOut, reason);
644 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
648 if (newActiveFocusItem && activeFocusItem == newActiveFocusItem) {
649 QFocusEvent event(QEvent::FocusIn, reason);
650 QCoreApplication::sendEvent(newActiveFocusItem, &event);
653 QQuickWindow *rootItemWindow = rootItem->window();
654 if (activeFocusItem != currentActiveFocusItem && rootItemWindow)
655 emit rootItemWindow->focusObjectChanged(activeFocusItem);
657 if (!changed.isEmpty())
658 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
659 if (isSubsceneAgent && rootItemWindow) {
660 auto da = QQuickWindowPrivate::get(rootItemWindow)->deliveryAgent;
661 qCDebug(lcFocus) <<
" delegating clearFocusInScope to" << da;
662 QQuickWindowPrivate::get(rootItemWindow)->deliveryAgentPrivate()->clearFocusInScope(da->rootItem(), item, reason, options);
664 if (oldActiveFocusItem == activeFocusItem)
665 qCDebug(lcFocus) <<
"activeFocusItem remains" << activeFocusItem <<
"in" << q;
667 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
670void QQuickDeliveryAgentPrivate::clearFocusObject()
672 if (activeFocusItem == rootItem)
675 clearFocusInScope(rootItem, QQuickItemPrivate::get(rootItem)->subFocusItem, Qt::OtherFocusReason);
678void QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(QQuickItem **items,
int remaining, Qt::FocusReason reason)
680 QPointer<QQuickItem> item(*items);
683 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
685 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
686 itemPrivate->notifiedFocus = itemPrivate->focus;
687 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
688 emit item->focusChanged(itemPrivate->focus);
691 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
692 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
693 itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged,
bool(itemPrivate->activeFocus));
694 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
695 emit item->activeFocusChanged(itemPrivate->activeFocus);
700 notifyFocusChangesRecur(items + 1, remaining - 1, reason);
703bool QQuickDeliveryAgentPrivate::clearHover(ulong timestamp)
705 if (hoverItems.isEmpty())
708 QQuickWindow *window = rootItem->window();
712 const auto globalPos = QGuiApplicationPrivate::lastCursorPosition;
713 const QPointF lastPos = window->mapFromGlobal(globalPos);
714 const auto modifiers = QGuiApplication::keyboardModifiers();
722 for (
auto it = hoverItems.cbegin(); it != hoverItems.cend(); ++it) {
723 if (QQuickItem *item = it->item) {
724 deliverHoverEventToItem(item, item->mapFromScene(lastPos), lastPos, lastPos,
725 globalPos, modifiers, timestamp, HoverChange::Clear);
726 Q_ASSERT(([
this, item]{
727 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
728 return it2 == hoverItems.cend() || it2->hoverId == 0;
737
738
739
740
741
742
743
744bool QQuickDeliveryAgentPrivate::isHoveredByHoveringDevice(
const QQuickItem *item)
const
746 const auto it = findHoverStateByItem(hoverItems, item);
747 if (it != hoverItems.cend() && it->hoverId != 0 && !it->fromTouch)
756 const QPointF cursorScenePos =
757 item->window()->mapFromGlobal(QPointF(QGuiApplicationPrivate::lastCursorPosition));
758 return item->contains(item->mapFromScene(cursorScenePos));
762
763
764
765
766
767
768
769
770
771void QQuickDeliveryAgentPrivate::clearTouchHover(ulong timestamp)
773 if (hoverItems.isEmpty())
776 QQuickWindow *window = rootItem->window();
780 const auto globalPos = QGuiApplicationPrivate::lastCursorPosition;
781 const QPointF lastPos = window->mapFromGlobal(globalPos);
782 const auto modifiers = QGuiApplication::keyboardModifiers();
786 QVarLengthArray<QPointer<QQuickItem>, 4> toClear;
787 for (
auto it = hoverItems.cbegin(); it != hoverItems.cend(); ++it) {
788 if (it->item && it->fromTouch && !isHoveredByHoveringDevice(it->item))
789 toClear.append(it->item);
792 for (
const auto &item : toClear) {
799 deliverHoverEventToItem(item, item->mapFromScene(lastPos), lastPos, lastPos,
800 globalPos, modifiers, timestamp, HoverChange::Clear);
804void QQuickDeliveryAgentPrivate::updateFocusItemTransform()
807 if (activeFocusItem && QGuiApplication::focusObject() == activeFocusItem) {
808 QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(activeFocusItem);
809 QGuiApplication::inputMethod()->setInputItemTransform(focusPrivate->itemToWindowTransform());
810 QGuiApplication::inputMethod()->setInputItemRectangle(QRectF(0, 0, focusPrivate->width, focusPrivate->height));
811 activeFocusItem->updateInputMethod(Qt::ImInputItemClipRectangle);
817
818
819
820QQuickItem *QQuickDeliveryAgentPrivate::focusTargetItem()
const
823 return activeFocusItem;
826 QQuickItem *targetItem = rootItem;
828 while (targetItem->isFocusScope()
829 && targetItem->scopedFocusItem()
830 && targetItem->scopedFocusItem()->isEnabled()) {
831 targetItem = targetItem->scopedFocusItem();
838
839
840
841
842
843QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(
const QQuickItem *item)
845 if (currentEventDeliveryAgent)
846 return currentEventDeliveryAgent;
848 return QQuickItemPrivate::get(
const_cast<QQuickItem *>(item))->deliveryAgent();
853
854
855
856
857QQuickDeliveryAgent::QQuickDeliveryAgent(QQuickItem *rootItem)
858 : QObject(*
new QQuickDeliveryAgentPrivate(rootItem), rootItem)
862QQuickDeliveryAgent::~QQuickDeliveryAgent()
866QQuickDeliveryAgent::Transform::~Transform()
871
872
873
874QQuickItem *QQuickDeliveryAgent::rootItem()
const
876 Q_D(
const QQuickDeliveryAgent);
881
882
883
884
885QQuickDeliveryAgent::Transform *QQuickDeliveryAgent::sceneTransform()
const
887 Q_D(
const QQuickDeliveryAgent);
888 return d->sceneTransform;
892
893
894
895
896void QQuickDeliveryAgent::setSceneTransform(QQuickDeliveryAgent::Transform *transform)
898 Q_D(QQuickDeliveryAgent);
899 if (d->sceneTransform == transform)
901 qCDebug(lcPtr) <<
this << d->sceneTransform <<
"->" << transform;
902 if (d->sceneTransform)
903 delete d->sceneTransform;
904 d->sceneTransform = transform;
908
909
910
911
912
913
914bool QQuickDeliveryAgent::event(QEvent *ev)
916 Q_D(QQuickDeliveryAgent);
917 d->currentEventDeliveryAgent =
this;
918 auto cleanup = qScopeGuard([d] { d->currentEventDeliveryAgent =
nullptr; });
920 switch (ev->type()) {
921 case QEvent::MouseButtonPress:
922 case QEvent::MouseButtonRelease:
923 case QEvent::MouseButtonDblClick:
924 case QEvent::MouseMove: {
925 QMouseEvent *me =
static_cast<QMouseEvent*>(ev);
926 d->handleMouseEvent(me);
929 case QEvent::HoverEnter:
930 case QEvent::HoverLeave:
931 case QEvent::HoverMove: {
932 QHoverEvent *he =
static_cast<QHoverEvent*>(ev);
935 d->lastMousePositionFromTouch =
false;
936 bool accepted = d->deliverHoverEvent(he->scenePosition(),
937 he->points().first().sceneLastPosition(),
938 he->modifiers(), he->timestamp());
939 d->lastMousePosition = he->scenePosition();
940 he->setAccepted(accepted);
942 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(d->sceneTransform ?
943 d->sceneTransform->map(he->scenePosition()) : he->scenePosition(), d->rootItem);
947 case QEvent::TouchBegin:
948 case QEvent::TouchUpdate:
949 case QEvent::TouchEnd: {
950 QTouchEvent *touch =
static_cast<QTouchEvent*>(ev);
951 d->handleTouchEvent(touch);
952 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
959 case QEvent::TouchCancel:
961 return d->deliverTouchCancelEvent(
static_cast<QTouchEvent*>(ev));
963 case QEvent::Enter: {
966 QEnterEvent *enter =
static_cast<QEnterEvent*>(ev);
967 const auto scenePos = enter->scenePosition();
968 d->lastMousePositionFromTouch =
false;
969 bool accepted = d->deliverHoverEvent(scenePos,
970 enter->points().first().sceneLastPosition(),
971 enter->modifiers(), enter->timestamp());
972 d->lastMousePosition = scenePos;
974 Q_ASSERT(enter->scenePosition() == scenePos);
975 enter->setAccepted(accepted);
977 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(enter->scenePosition(), d->rootItem);
983 d->lastMousePosition = QPointF();
984 d->lastMousePositionFromTouch =
false;
986#if QT_CONFIG(quick_draganddrop)
987 case QEvent::DragEnter:
988 case QEvent::DragLeave:
989 case QEvent::DragMove:
991 d->deliverDragEvent(d->dragGrabber, ev);
994 case QEvent::FocusAboutToChange:
996 if (d->activeFocusItem)
997 qGuiApp->inputMethod()->commit();
1000#if QT_CONFIG(gestures)
1001 case QEvent::NativeGesture:
1002 d->deliverSinglePointEventUntilAccepted(
static_cast<QPointerEvent *>(ev));
1005 case QEvent::ShortcutOverride:
1006 d->deliverKeyEvent(
static_cast<QKeyEvent *>(ev));
1008 case QEvent::InputMethod:
1009 case QEvent::InputMethodQuery:
1011 QQuickItem *target = d->focusTargetItem();
1013 QCoreApplication::sendEvent(target, ev);
1016#if QT_CONFIG(wheelevent)
1017 case QEvent::Wheel: {
1018 auto event =
static_cast<QWheelEvent *>(ev);
1019 qCDebug(lcMouse) << event;
1022 if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate)
1026 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
1027 event->angleDelta().x(), event->angleDelta().y());
1028 d->deliverSinglePointEventUntilAccepted(event);
1029 d->lastWheelEventAccepted = event->isAccepted();
1033#if QT_CONFIG(tabletevent)
1034 case QEvent::TabletPress:
1035 case QEvent::TabletMove:
1036 case QEvent::TabletRelease:
1038 auto *tabletEvent =
static_cast<QTabletEvent *>(ev);
1039 d->deliverPointerEvent(tabletEvent);
1040#if QT_CONFIG(cursor)
1041 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(tabletEvent->scenePosition(), d->rootItem);
1046#ifndef QT_NO_CONTEXTMENU
1047 case QEvent::ContextMenu:
1048 d->deliverContextMenuEvent(
static_cast<QContextMenuEvent *>(ev));
1052 Q_ASSERT(
static_cast<QTimerEvent *>(ev)->timerId() == d->frameSynchronousDelayTimer.timerId());
1053 d->frameSynchronousDelayTimer.stop();
1054 d->flushFrameSynchronousEvents(d->rootItem->window());
1063void QQuickDeliveryAgentPrivate::deliverKeyEvent(QKeyEvent *e)
1065 if (activeFocusItem) {
1066 const bool keyPress = (e->type() == QEvent::KeyPress);
1067 switch (e->type()) {
1068 case QEvent::KeyPress:
1069 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(), e->modifiers());
1071 case QEvent::KeyRelease:
1072 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(), e->modifiers());
1078 QQuickItem *item = activeFocusItem;
1081 if (keyPress && e->spontaneous() ==
false)
1082 qt_sendShortcutOverrideEvent(item, e->timestamp(),
1083 e->key(), e->modifiers(), e->text(),
1084 e->isAutoRepeat(), e->count());
1087 Q_ASSERT(e->type() != QEvent::ShortcutOverride || !e->isAccepted());
1088 if (e->type() != QEvent::ShortcutOverride)
1090 QCoreApplication::sendEvent(item, e);
1091 }
while (!e->isAccepted() && (item = item->parentItem()));
1095QQuickDeliveryAgentPrivate::QQuickDeliveryAgentPrivate(QQuickItem *root) :
1099 isSubsceneAgent(!qmlobject_cast<QQuickRootItem *>(rootItem))
1101#if QT_CONFIG(quick_draganddrop)
1102 dragGrabber =
new QQuickDragGrabber;
1104 if (isSubsceneAgent)
1105 subsceneAgentsExist =
true;
1106 const auto interval = qEnvironmentVariableIntegerValue(
"QT_QUICK_FRAME_SYNCHRONOUS_HOVER_INTERVAL");
1107 if (interval.has_value()) {
1108 qCDebug(lcHoverTrace) <<
"frame-synchronous hover interval" << interval;
1109 frameSynchronousHoverInterval =
int(interval.value());
1111 if (frameSynchronousHoverInterval > 0)
1112 frameSynchronousHoverTimer.start();
1115QQuickDeliveryAgentPrivate::~QQuickDeliveryAgentPrivate()
1117#if QT_CONFIG(quick_draganddrop)
1119 dragGrabber =
nullptr;
1121 delete sceneTransform;
1125
1126
1127
1128
1129
1130
1131QPointerEvent *QQuickDeliveryAgentPrivate::clonePointerEvent(QPointerEvent *event, std::optional<QPointF> transformedLocalPos)
1133 QPointerEvent *ret = event->clone();
1134 QEventPoint &point = ret->point(0);
1135 QMutableEventPoint::detach(point);
1136 QMutableEventPoint::setTimestamp(point, event->timestamp());
1137 if (transformedLocalPos)
1138 QMutableEventPoint::setPosition(point, *transformedLocalPos);
1143void QQuickDeliveryAgentPrivate::deliverToPassiveGrabbers(
const QList<QPointer <QObject> > &passiveGrabbers,
1144 QPointerEvent *pointerEvent)
1146 const QList<QObject *> &eventDeliveryTargets =
1147 QQuickPointerHandlerPrivate::deviceDeliveryTargets(pointerEvent->device());
1148 QVarLengthArray<std::pair<QQuickItem *,
bool>, 4> sendFilteredPointerEventResult;
1149 hasFiltered.clear();
1150 for (QObject *grabberObject : passiveGrabbers) {
1152 if (Q_UNLIKELY(!grabberObject))
1155 if (QQuickPointerHandler *handler = qobject_cast<QQuickPointerHandler *>(grabberObject)) {
1156 if (handler && !eventDeliveryTargets.contains(handler)) {
1157 bool alreadyFiltered =
false;
1158 QQuickItem *par = handler->parentItem();
1161 auto it = std::find_if(sendFilteredPointerEventResult.begin(), sendFilteredPointerEventResult.end(),
1162 [par](
const std::pair<QQuickItem *,
bool> &pair) {
return pair.first == par; });
1163 if (it != sendFilteredPointerEventResult.end()) {
1166 alreadyFiltered = it->second;
1168 alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par);
1169 sendFilteredPointerEventResult << std::make_pair(par, alreadyFiltered);
1171 if (!alreadyFiltered) {
1173 localizePointerEvent(pointerEvent, par);
1174 handler->handlePointerEvent(pointerEvent);
1177 }
else if (QQuickItem *grabberItem =
static_cast<QQuickItem *>(grabberObject)) {
1179 if (QQuickItem *excGrabber =
static_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(pointerEvent->point(0)))) {
1180 if ((isMouseEvent(pointerEvent) && excGrabber->keepMouseGrab())
1181 || (isTouchEvent(pointerEvent) && excGrabber->keepTouchGrab())) {
1185 localizePointerEvent(pointerEvent, grabberItem);
1186 QCoreApplication::sendEvent(grabberItem, pointerEvent);
1187 pointerEvent->accept();
1192bool QQuickDeliveryAgentPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1193 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1194 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp)
1196 QHoverEvent hoverEvent(type, scenePos, globalPos, lastScenePos, modifiers);
1197 hoverEvent.setTimestamp(timestamp);
1198 hoverEvent.setAccepted(
true);
1199 QEventPoint &point = hoverEvent.point(0);
1200 QMutableEventPoint::setPosition(point, localPos);
1201 if (Q_LIKELY(item->window()))
1202 QMutableEventPoint::setGlobalLastPosition(point, item->window()->mapToGlobal(lastScenePos));
1204 hasFiltered.clear();
1205 if (sendFilteredMouseEvent(&hoverEvent, item, item->parentItem()))
1208 QCoreApplication::sendEvent(item, &hoverEvent);
1210 return hoverEvent.isAccepted();
1214
1215
1216
1217
1219bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
1220 const QPointF &scenePos,
const QPointF &lastScenePos,
1221 Qt::KeyboardModifiers modifiers, ulong timestamp)
1239 const bool subtreeHoverEnabled = QQuickItemPrivate::get(rootItem)->subtreeHoverEnabled;
1240 const bool itemsWasHovered = !hoverItems.isEmpty();
1242 if (!subtreeHoverEnabled && !itemsWasHovered)
1247 if (subtreeHoverEnabled) {
1248 hoveredLeafItemFound =
false;
1249 QQuickPointerHandlerPrivate::deviceDeliveryTargets(QPointingDevice::primaryPointingDevice()).clear();
1250 deliverHoverEventRecursive(rootItem, scenePos, scenePos, lastScenePos,
1251 rootItem->mapToGlobal(scenePos), modifiers, timestamp);
1255 for (
auto it = hoverItems.begin(); it != hoverItems.end();) {
1256 const auto &[item, hoverId, fromFinger] = *it;
1257 if (hoverId == currentHoverId) {
1264 if (item && hoverId != 0)
1265 deliverHoverEventToItem(item, item->mapFromScene(scenePos), scenePos, lastScenePos,
1266 QGuiApplicationPrivate::lastCursorPosition, modifiers, timestamp, HoverChange::Clear);
1267 it = hoverItems.erase(it);
1271 const bool itemsAreHovered = !hoverItems.isEmpty();
1272 return itemsWasHovered || itemsAreHovered;
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(QQuickItem *item,
1312 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
const QPointF &globalPos,
1313 Qt::KeyboardModifiers modifiers, ulong timestamp)
1315 const QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1316 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1317 const bool hadChildrenChanged = itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged;
1319 for (
int ii = children.size() - 1; ii >= 0; --ii) {
1323 if (!hadChildrenChanged && Q_UNLIKELY(itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged))
1325 QQuickItem *child = children.at(ii);
1326 const QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
1328 if (!child->isVisible() || childPrivate->culled)
1330 if (!childPrivate->subtreeHoverEnabled)
1333 QTransform childToParent;
1334 childPrivate->itemToParentTransform(&childToParent);
1335 const QPointF childLocalPos = childToParent.inverted().map(localPos);
1340 if (childPrivate->effectivelyClipsEventHandlingChildren() &&
1341 !childPrivate->eventHandlingBounds().contains(childLocalPos)) {
1342#ifdef QT_BUILD_INTERNAL
1343 ++QQuickItemPrivate::effectiveClippingSkips_counter;
1349 const bool accepted = deliverHoverEventRecursive(child, childLocalPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1354 if (hoveredLeafItemFound) {
1362 return deliverHoverEventToItem(item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp, HoverChange::Set);
1366
1367
1368
1369
1370
1371
1372
1373bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1374 QQuickItem *item,
const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1375 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp, HoverChange hoverChange)
1377 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1378 const bool isHovering = item->contains(localPos);
1379 auto hoverItemIterator = findHoverStateByItem(hoverItems, item);
1380 const bool wasHovering = hoverItemIterator != hoverItems.end() && hoverItemIterator->hoverId != 0;
1382 qCDebug(lcHoverTrace) <<
"item:" << item <<
"scene pos:" << scenePos <<
"localPos:" << localPos
1383 <<
"wasHovering:" << wasHovering <<
"isHovering:" << isHovering;
1385 bool accepted =
false;
1390 if (itemPrivate->hoverEnabled && isHovering && hoverChange == HoverChange::Set) {
1395 hoveredLeafItemFound =
true;
1396 if (hoverItemIterator != hoverItems.end())
1397 markHovered(*hoverItemIterator, currentHoverId, lastMousePositionFromTouch);
1399 hoverItems.append({item, currentHoverId, lastMousePositionFromTouch});
1402 accepted = sendHoverEvent(QEvent::HoverMove, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1404 accepted = sendHoverEvent(QEvent::HoverEnter, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1405 }
else if (wasHovering) {
1407 hoverItemIterator->hoverId = 0;
1408 sendHoverEvent(QEvent::HoverLeave, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1411 if (!itemPrivate->hasPointerHandlers())
1421 if (hoverChange == HoverChange::Clear) {
1423 QHoverEvent hoverEvent(QEvent::HoverLeave, scenePos, globalPos, lastScenePos, modifiers);
1424 hoverEvent.setTimestamp(timestamp);
1426 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1427 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1428 if (!hh->isHovered())
1430 hoverEvent.setAccepted(
true);
1431 QCoreApplication::sendEvent(hh, &hoverEvent);
1435 QMouseEvent hoverEvent(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, Qt::NoButton, modifiers);
1436 hoverEvent.setTimestamp(timestamp);
1438 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1439 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1442 hoverEvent.setAccepted(
true);
1443 hh->handlePointerEvent(&hoverEvent);
1444 if (hh->isHovered()) {
1447 hoveredLeafItemFound =
true;
1448 hoverItemIterator = findHoverStateByItem(hoverItems, item);
1449 if (hoverItemIterator != hoverItems.end())
1450 markHovered(*hoverItemIterator, currentHoverId, lastMousePositionFromTouch);
1452 hoverItems.append({item, currentHoverId, lastMousePositionFromTouch});
1453 if (hh->isBlocking()) {
1454 qCDebug(lcHoverTrace) <<
"skipping rest of hover delivery due to blocking" << hh;
1468bool QQuickDeliveryAgentPrivate::deliverSinglePointEventUntilAccepted(QPointerEvent *event)
1470 Q_ASSERT(event->points().size() == 1);
1471 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
1472 QEventPoint &point = event->point(0);
1473 QList<QQuickItem *> targetItems = pointerTargets(rootItem, event, point,
false,
false);
1474 point.setAccepted(
false);
1479 for (
const auto &passiveGrabber : event->passiveGrabbers(point)) {
1480 if (
auto *grabberItem = qobject_cast<QQuickItem *>(passiveGrabber)) {
1481 if (targetItems.contains(grabberItem))
1483 localizePointerEvent(event, grabberItem);
1484 QCoreApplication::sendEvent(grabberItem, event);
1491 for (QQuickItem *item : targetItems) {
1492 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1493 localizePointerEvent(event, item);
1495 itemPrivate->handlePointerEvent(event);
1496 if (point.isAccepted())
1499 QCoreApplication::sendEvent(item, event);
1500 if (event->isAccepted()) {
1501 qCDebug(lcWheelTarget) << event <<
"->" << item;
1509bool QQuickDeliveryAgentPrivate::deliverTouchCancelEvent(QTouchEvent *event)
1511 qCDebug(lcTouch) << event;
1516 const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(event->pointingDevice()))->
1517 sendTouchCancelEvent(event);
1519 cancelTouchMouseSynthesis();
1523 if (event->pointerType() == QPointingDevice::PointerType::Finger)
1524 clearTouchHover(event->timestamp());
1527 lastMousePosition = {};
1528 lastMousePositionFromTouch =
false;
1533void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent()
1538 std::unique_ptr<QTouchEvent> e(std::move(delayedTouch));
1539 qCDebug(lcTouchCmprs) <<
"delivering" << e.get();
1540 compressedTouchCount = 0;
1541 deliverPointerEvent(e.get());
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
1556 Q_Q(QQuickDeliveryAgent);
1557 qCDebug(lcFocus) <<
"deactivated" << win->title();
1558 const auto inputDevices = QInputDevice::devices();
1559 for (
auto device : inputDevices) {
1560 if (
auto pointingDevice = qobject_cast<
const QPointingDevice *>(device)) {
1561 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(pointingDevice));
1562 for (
auto epd : devPriv->activePoints.values()) {
1563 if (!epd.exclusiveGrabber.isNull()) {
1564 bool relevant =
false;
1565 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(epd.exclusiveGrabber.data()))
1566 relevant = (item->window() == win);
1567 else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(epd.exclusiveGrabber.data())) {
1568 if (handler->parentItem())
1569 relevant = (handler->parentItem()->window() == win && epd.exclusiveGrabberContext.data() == q);
1576 devPriv->setExclusiveGrabber(
nullptr, epd.eventPoint,
nullptr);
1585void QQuickDeliveryAgentPrivate::handleWindowHidden(QQuickWindow *win)
1587 qCDebug(lcFocus) <<
"hidden" << win->title();
1589 lastMousePosition = QPointF();
1590 lastMousePositionFromTouch =
false;
1593bool QQuickDeliveryAgentPrivate::allUpdatedPointsAccepted(
const QPointerEvent *ev)
1595 for (
auto &point : ev->points()) {
1596 if (point.state() != QEventPoint::State::Pressed && !point.isAccepted())
1603
1604
1605
1606
1607
1608void QQuickDeliveryAgentPrivate::localizePointerEvent(QPointerEvent *ev,
const QQuickItem *dest)
1610 for (
int i = 0; i < ev->pointCount(); ++i) {
1611 auto &point = ev->point(i);
1612 QMutableEventPoint::setPosition(point, dest->mapFromScene(point.scenePosition()));
1613 qCDebug(lcPtrLoc) << ev->type() <<
"@" << point.scenePosition() <<
"to"
1614 << dest <<
"@" << dest->mapToScene(QPointF()) <<
"->" << point;
1618QList<QObject *> QQuickDeliveryAgentPrivate::exclusiveGrabbers(QPointerEvent *ev)
1620 QList<QObject *> result;
1621 for (
const QEventPoint &point : ev->points()) {
1622 if (QObject *grabber = ev->exclusiveGrabber(point)) {
1623 if (!result.contains(grabber))
1630bool QQuickDeliveryAgentPrivate::anyPointGrabbed(
const QPointerEvent *ev)
1632 for (
const QEventPoint &point : ev->points()) {
1633 if (ev->exclusiveGrabber(point) || !ev->passiveGrabbers(point).isEmpty())
1639bool QQuickDeliveryAgentPrivate::allPointsGrabbed(
const QPointerEvent *ev)
1641 for (
const auto &point : ev->points()) {
1642 if (!ev->exclusiveGrabber(point) && ev->passiveGrabbers(point).isEmpty())
1648bool QQuickDeliveryAgentPrivate::isMouseEvent(
const QPointerEvent *ev)
1650 switch (ev->type()) {
1651 case QEvent::MouseButtonPress:
1652 case QEvent::MouseButtonRelease:
1653 case QEvent::MouseButtonDblClick:
1654 case QEvent::MouseMove:
1661bool QQuickDeliveryAgentPrivate::isMouseOrWheelEvent(
const QPointerEvent *ev)
1663 return isMouseEvent(ev) || ev->type() == QEvent::Wheel;
1666bool QQuickDeliveryAgentPrivate::isHoverEvent(
const QPointerEvent *ev)
1668 switch (ev->type()) {
1669 case QEvent::HoverEnter:
1670 case QEvent::HoverMove:
1671 case QEvent::HoverLeave:
1678bool QQuickDeliveryAgentPrivate::isTouchEvent(
const QPointerEvent *ev)
1680 switch (ev->type()) {
1681 case QEvent::TouchBegin:
1682 case QEvent::TouchUpdate:
1683 case QEvent::TouchEnd:
1684 case QEvent::TouchCancel:
1691bool QQuickDeliveryAgentPrivate::isTabletEvent(
const QPointerEvent *ev)
1693#if QT_CONFIG(tabletevent)
1694 switch (ev->type()) {
1695 case QEvent::TabletPress:
1696 case QEvent::TabletMove:
1697 case QEvent::TabletRelease:
1698 case QEvent::TabletEnterProximity:
1699 case QEvent::TabletLeaveProximity:
1710bool QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(
const QPointerEvent *ev)
1712 const auto devType = ev->device()->type();
1713 return devType == QInputDevice::DeviceType::Mouse ||
1714 devType == QInputDevice::DeviceType::TouchPad;
1717bool QQuickDeliveryAgentPrivate::isSynthMouse(
const QPointerEvent *ev)
1719 return (!isEventFromMouseOrTouchpad(ev) && isMouseEvent(ev));
1723
1724
1725
1726bool QQuickDeliveryAgentPrivate::isSinglePointDevice(
const QInputDevice *dev)
1728 switch (dev->type()) {
1729 case QInputDevice::DeviceType::Mouse:
1730 case QInputDevice::DeviceType::TouchPad:
1731 case QInputDevice::DeviceType::Puck:
1732 case QInputDevice::DeviceType::Stylus:
1733 case QInputDevice::DeviceType::Airbrush:
1735 case QInputDevice::DeviceType::TouchScreen:
1736 case QInputDevice::DeviceType::Keyboard:
1737 case QInputDevice::DeviceType::Unknown:
1738 case QInputDevice::DeviceType::AllDevices:
1745
1746
1747bool QQuickDeliveryAgentPrivate::isTouchPadWithMouseEmulation(
const QInputDevice *device)
1749 return device->type() == QInputDevice::DeviceType::TouchPad
1750 && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation);
1753QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(
const QInputDevice *device)
1755 QInputDevicePrivate *devPriv = QInputDevicePrivate::get(
const_cast<QInputDevice *>(device));
1756 if (devPriv->qqExtra)
1757 return static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1758 auto extra =
new QQuickPointingDeviceExtra;
1759 devPriv->qqExtra = extra;
1760 QObject::connect(device, &QObject::destroyed, device, [devPriv]() {
1761 delete static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1762 devPriv->qqExtra =
nullptr;
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
1795 if (isSubsceneAgent)
1798 QEventPoint::States states = event->touchPointStates();
1799 if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
1800 qCDebug(lcTouchCmprs) <<
"no compression" << event;
1805 if (!delayedTouch) {
1806 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points()));
1807 delayedTouch->setTimestamp(event->timestamp());
1808 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1809 auto &tp = delayedTouch->point(i);
1810 QMutableEventPoint::detach(tp);
1812 ++compressedTouchCount;
1813 qCDebug(lcTouchCmprs) <<
"delayed" << compressedTouchCount << delayedTouch.get();
1814 if (QQuickWindow *window = rootItem->window())
1815 window->maybeUpdate();
1820 if (delayedTouch->type() == event->type() &&
1821 delayedTouch->device() == event->device() &&
1822 delayedTouch->modifiers() == event->modifiers() &&
1823 delayedTouch->pointCount() == event->pointCount())
1826 bool mismatch =
false;
1828 auto tpts = event->points();
1829 for (qsizetype i = 0; i < event->pointCount(); ++i) {
1830 const auto &tp = tpts.at(i);
1831 const auto &tpDelayed = delayedTouch->point(i);
1832 if (tp.id() != tpDelayed.id()) {
1837 if (tpDelayed.state() == QEventPoint::State::Updated && tp.state() == QEventPoint::State::Stationary)
1838 QMutableEventPoint::setState(tpts[i], QEventPoint::State::Updated);
1845 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts));
1846 delayedTouch->setTimestamp(event->timestamp());
1847 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1848 auto &tp = delayedTouch->point(i);
1849 QMutableEventPoint::detach(tp);
1851 ++compressedTouchCount;
1852 qCDebug(lcTouchCmprs) <<
"coalesced" << compressedTouchCount << delayedTouch.get();
1853 if (QQuickWindow *window = rootItem->window())
1854 window->maybeUpdate();
1860 deliverDelayedTouchEvent();
1861 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(),
1862 event->modifiers(), event->points()));
1863 delayedTouch->setTimestamp(event->timestamp());
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1880 if (!event->isEndEvent())
1882 if (!event->pointCount())
1885 if (Q_UNLIKELY(event->pointerType() != QPointingDevice::PointerType::Finger))
1890 const auto *devPriv = QPointingDevicePrivate::get(event->pointingDevice());
1891 for (
const auto &activePoint : devPriv->activePoints) {
1892 if (activePoint.second.eventPoint.state() != QEventPoint::State::Released)
1902void QQuickDeliveryAgentPrivate::handleTouchEvent(QTouchEvent *event)
1904 Q_Q(QQuickDeliveryAgent);
1905 translateTouchEvent(event);
1907 if (event->pointCount() && !isTouchPadWithMouseEmulation(event->device())) {
1908 auto &point = event->point(0);
1909 if (point.state() == QEventPoint::State::Released) {
1913 lastMousePosition = QPointF();
1914 lastMousePositionFromTouch =
false;
1916 lastMousePosition = point.position();
1917 lastMousePositionFromTouch =
1918 event->pointerType() == QPointingDevice::PointerType::Finger;
1925 const bool fingerHoverEnded = isEndOfFingerTouchSequence(event);
1927 qCDebug(lcTouch) << q << event;
1929 static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet(
"QML_NO_TOUCH_COMPRESSION");
1931 if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) {
1932 deliverPointerEvent(event);
1933 }
else if (!compressTouchEvent(event)) {
1935 deliverDelayedTouchEvent();
1936 qCDebug(lcTouchCmprs) <<
"resuming delivery" << event;
1938 deliverPointerEvent(event);
1943 if (fingerHoverEnded)
1944 clearTouchHover(event->timestamp());
1948
1949
1950void QQuickDeliveryAgentPrivate::handleMouseEvent(QMouseEvent *event)
1952 Q_Q(QQuickDeliveryAgent);
1956 if (event->source() == Qt::MouseEventSynthesizedBySystem &&
1957 !(event->button() == Qt::RightButton && allowSyntheticRightClick())) {
1961 qCDebug(lcMouse) << q << event;
1963 switch (event->type()) {
1964 case QEvent::MouseButtonPress:
1965 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
1967 deliverPointerEvent(event);
1969 case QEvent::MouseButtonRelease:
1970 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
1972 deliverPointerEvent(event);
1973#if QT_CONFIG(cursor)
1974 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1977 case QEvent::MouseButtonDblClick:
1978 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1979 event->button(), event->buttons());
1980 deliverPointerEvent(event);
1982 case QEvent::MouseMove: {
1983 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
1984 event->position().x(), event->position().y());
1986 const QPointF last = lastMousePosition.isNull() ? event->scenePosition() : lastMousePosition;
1987 lastMousePosition = event->scenePosition();
1990 lastMousePositionFromTouch =
false;
1991 qCDebug(lcHoverTrace) << q <<
"mouse pos" << last <<
"->" << lastMousePosition;
1992 if (!event->points().size() || !event->exclusiveGrabber(event->point(0))) {
1993 bool accepted = deliverHoverEvent(event->scenePosition(), last, event->modifiers(), event->timestamp());
1994 event->setAccepted(accepted);
1996 deliverPointerEvent(event);
1997#if QT_CONFIG(cursor)
1999 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024void QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents(QQuickWindow *win)
2026 Q_Q(QQuickDeliveryAgent);
2027 QQuickDeliveryAgent *deliveringAgent = QQuickDeliveryAgentPrivate::currentEventDeliveryAgent;
2028 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = q;
2031 deliverDelayedTouchEvent();
2035 QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
2036 if (ut && ut->hasStartAnimationPending())
2037 ut->startAnimations();
2042#if !defined(Q_OS_WEBOS)
2052 if (frameSynchronousHoverInterval >= 0) {
2053 const bool timerActive = frameSynchronousHoverInterval > 0;
2054 const bool timerMature = frameSynchronousHoverTimer.elapsed() >= frameSynchronousHoverInterval;
2055 if (timerActive && !timerMature) {
2056 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery delayed: elapsed"
2057 << frameSynchronousHoverTimer.elapsed() <<
"<" << frameSynchronousHoverInterval;
2058 if (!frameSynchronousDelayTimer.isActive())
2059 frameSynchronousDelayTimer.start(frameSynchronousHoverInterval - frameSynchronousHoverTimer.elapsed(), q);
2060 }
else if (!win->mouseGrabberItem() && !lastMousePosition.isNull() &&
2061 (timerMature || QQuickWindowPrivate::get(win)->dirtyItemList)) {
2062 frameSynchronousDelayTimer.stop();
2063 qCDebug(lcHoverTrace) << q <<
"delivering frame-sync hover to root @" << lastMousePosition
2064 <<
"after elapsed time" << frameSynchronousHoverTimer.elapsed();
2065 if (deliverHoverEvent(lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0)) {
2066#if QT_CONFIG(cursor)
2067 QQuickWindowPrivate::get(rootItem->window())->updateCursor(
2068 sceneTransform ? sceneTransform->map(lastMousePosition) : lastMousePosition, rootItem);
2073 frameSynchronousHoverTimer.restart();
2074 ++frameSynchronousHover_counter;
2075 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery done: round" << frameSynchronousHover_counter;
2081 if (Q_UNLIKELY(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent &&
2082 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent != q))
2083 qCWarning(lcPtr,
"detected interleaved frame-sync and actual events");
2084 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveringAgent;
2088
2089
2090
2091
2092
2093
2094
2095void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition,
2096 const QPointerEvent *event,
const QEventPoint &point)
2098 Q_Q(QQuickDeliveryAgent);
2099 const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
2100 transition == QPointingDevice::GrabTransition::GrabPassive);
2103 if (
auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
2104 if (handler->parentItem()) {
2105 auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
2106 if (itemPriv->deliveryAgent() == q) {
2108 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
2109 const_cast<QEventPoint &>(point));
2114 QEventPoint lostPoint(point);
2115 QMutableEventPoint::setPosition(lostPoint, handler->parentItem()->mapFromScene(point.scenePosition()));
2116 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
2118 qCDebug(lcPtrLoc) << event->type() <<
"@" << point.scenePosition()
2119 <<
"to old handler" << grabber <<
"->" << lostPoint;
2125 if (isSubsceneAgent && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
2126 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
2128 }
else if (!isSubsceneAgent) {
2129 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
2130 const_cast<QEventPoint &>(point));
2132 }
else if (
auto *grabberItem = qmlobject_cast<QQuickItem *>(grabber)) {
2133 switch (transition) {
2134 case QPointingDevice::CancelGrabExclusive:
2135 case QPointingDevice::UngrabExclusive:
2136 if (isDeliveringTouchAsMouse() || isSinglePointDevice(point.device())) {
2139 QMutableSinglePointEvent e(QEvent::UngrabMouse, point.device(), point);
2140 hasFiltered.clear();
2141 if (!sendFilteredMouseEvent(&e, grabberItem, grabberItem->parentItem())) {
2142 lastUngrabbed = grabberItem;
2143 grabberItem->mouseUngrabEvent();
2148 bool allReleasedOrCancelled =
true;
2149 if (transition == QPointingDevice::UngrabExclusive && event) {
2150 for (
const auto &pt : event->points()) {
2151 if (pt.state() != QEventPoint::State::Released) {
2152 allReleasedOrCancelled =
false;
2157 if (allReleasedOrCancelled)
2158 grabberItem->touchUngrabEvent();
2164 auto *itemPriv = QQuickItemPrivate::get(grabberItem);
2167 if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
2168 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
2171 if (currentEventDeliveryAgent == q && event && event->device()) {
2172 switch (transition) {
2173 case QPointingDevice::GrabPassive: {
2174 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2176 QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q);
2177 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2179 case QPointingDevice::GrabExclusive: {
2180 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2182 epd->exclusiveGrabberContext = q;
2183 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2185 case QPointingDevice::CancelGrabExclusive:
2186 case QPointingDevice::UngrabExclusive:
2189 case QPointingDevice::UngrabPassive:
2190 case QPointingDevice::CancelGrabPassive:
2193 case QPointingDevice::OverrideGrabPassive:
2201
2202
2203
2204
2205
2206
2207
2208
2209void QQuickDeliveryAgentPrivate::ensureDeviceConnected(
const QPointingDevice *dev)
2211 Q_Q(QQuickDeliveryAgent);
2212 if (knownPointingDevices.contains(dev))
2214 knownPointingDevices.append(dev);
2215 connect(dev, &QPointingDevice::grabChanged,
this, &QQuickDeliveryAgentPrivate::onGrabChanged);
2216 QObject::connect(dev, &QObject::destroyed, q, [
this, dev] {
this->knownPointingDevices.removeAll(dev);});
2220
2221
2222
2223
2224
2225
2226void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
2228 Q_Q(QQuickDeliveryAgent);
2229 if (isTabletEvent(event))
2230 qCDebug(lcTablet) << q << event;
2235 ++pointerEventRecursionGuard;
2236 eventsInDelivery.push(event);
2242 QVarLengthArray<QPointF, 16> originalScenePositions;
2243 if (sceneTransform) {
2244 originalScenePositions.resize(event->pointCount());
2245 for (
int i = 0; i < event->pointCount(); ++i) {
2246 auto &pt = event->point(i);
2247 originalScenePositions[i] = pt.scenePosition();
2248 QMutableEventPoint::setScenePosition(pt, sceneTransform->map(pt.scenePosition()));
2249 qCDebug(lcPtrLoc) << q << event->type() << pt.id() <<
"transformed scene pos" << pt.scenePosition();
2251 }
else if (isSubsceneAgent) {
2252 qCDebug(lcPtrLoc) << q << event->type() <<
"no scene transform set";
2255 skipDelivery.clear();
2256 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
2258 qCDebug(lcPtr) << q <<
"delivering with" << sceneTransform << event;
2260 qCDebug(lcPtr) << q <<
"delivering" << event;
2261 for (
int i = 0; i < event->pointCount(); ++i)
2262 event->point(i).setAccepted(
false);
2264 if (event->isBeginEvent()) {
2265 ensureDeviceConnected(event->pointingDevice());
2266 if (event->type() == QEvent::MouseButtonPress && rootItem->window()
2267 &&
static_cast<QSinglePointEvent *>(event)->button() == Qt::RightButton) {
2268 QQuickWindowPrivate::get(rootItem->window())->rmbContextMenuEventEnabled =
true;
2270 if (!deliverPressOrReleaseEvent(event))
2271 event->setAccepted(
false);
2274 auto isHoveringMoveEvent = [](QPointerEvent *event) ->
bool {
2275 if (event->type() == QEvent::MouseMove) {
2276 const auto *spe =
static_cast<
const QSinglePointEvent *>(event);
2277 if (spe->button() == Qt::NoButton && spe->buttons() == Qt::NoButton)
2284
2285
2286
2287
2288
2289
2290
2291
2292 if (!allUpdatedPointsAccepted(event) && !isHoveringMoveEvent(event))
2293 deliverUpdatedPoints(event);
2294 if (event->isEndEvent())
2295 deliverPressOrReleaseEvent(event,
true);
2299 if (isTouchEvent(event) && touchMouseId >= 0) {
2300 if (
static_cast<QTouchEvent *>(event)->touchPointStates() == QEventPoint::State::Released) {
2301 cancelTouchMouseSynthesis();
2303 auto touchMousePoint = event->pointById(touchMouseId);
2304 if (touchMousePoint && touchMousePoint->state() == QEventPoint::State::Released)
2305 cancelTouchMouseSynthesis();
2309 eventsInDelivery.pop();
2310 if (sceneTransform) {
2311 for (
int i = 0; i < event->pointCount(); ++i)
2312 QMutableEventPoint::setScenePosition(event->point(i), originalScenePositions.at(i));
2314 --pointerEventRecursionGuard;
2315 lastUngrabbed =
nullptr;
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355QList<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
const QEvent *event,
int pointId,
2356 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate)
const
2358 QList<QQuickItem *> targets;
2359 eventTargetsAppend(item, event, pointId, localPos, scenePos, predicate, targets);
2364
2365
2366
2367
2368
2370void QQuickDeliveryAgentPrivate::eventTargetsAppend(QQuickItem *item,
const QEvent *event,
int pointId,
2371 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate,
2372 QList<QQuickItem *> &targets)
const
2374 auto itemPrivate = QQuickItemPrivate::get(item);
2379 if (item != rootItem && !itemPrivate->eventHandlingBounds().contains(localPos) &&
2380 itemPrivate->effectivelyClipsEventHandlingChildren()) {
2381 qCDebug(lcPtrLoc) <<
"skipping because" << localPos <<
"is outside rectangular bounds of" << item;
2387 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2392 Q_ASSERT(event->isPointerEvent());
2393 QPointerEvent *pev =
const_cast<QPointerEvent *>(
static_cast<
const QPointerEvent *>(event));
2394 QEventPoint *point = pev->pointById(pointId);
2396 QMutableEventPoint::setPosition(*point, localPos);
2398 const std::optional<
bool> override = predicate(item, event);
2399 const bool relevant = override.has_value() ? override.value()
2400 : item == rootItem || item->contains(localPos);
2405 bool selfEmitted = !relevant;
2406 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2407 QQuickItem *child = children.at(ii);
2408 if (!selfEmitted && child->z() < 0) {
2409 targets.append(item);
2413 auto childPrivate = QQuickItemPrivate::get(child);
2414 if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
2415 (childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
2418 QTransform childToParent;
2419 childPrivate->itemToParentTransform(&childToParent);
2420 const QPointF childLocalPos = childToParent.inverted().map(localPos);
2421 eventTargetsAppend(child, event, pointId, childLocalPos, scenePos, predicate, targets);
2426 targets.append(item);
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458QList<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *item,
const QPointerEvent *event,
const QEventPoint &point,
2459 bool checkMouseButtons,
bool checkAcceptsTouch)
const
2461 auto predicate = [point, checkMouseButtons, checkAcceptsTouch](QQuickItem *item,
const QEvent *ev) -> std::optional<
bool> {
2462 const QPointerEvent *event =
static_cast<
const QPointerEvent *>(ev);
2463 auto itemPrivate = QQuickItemPrivate::get(item);
2464 if (itemPrivate->hasPointerHandlers()) {
2465 if (itemPrivate->anyPointerHandlerWants(event, point))
2468 if (checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
2470 if (checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
2474 return std::nullopt;
2477 return eventTargets(item, event, point.id(), item->mapFromScene(point.scenePosition()), point.scenePosition(), predicate);
2481
2482
2483
2484QList<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(
const QList<QQuickItem *> &list1,
const QList<QQuickItem *> &list2)
const
2486 QList<QQuickItem *> targets = list1;
2490 int insertPosition = targets.size();
2491 for (
int i = list2.size() - 1; i >= 0; --i) {
2492 int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
2493 if (newInsertPosition >= 0) {
2494 Q_ASSERT(newInsertPosition <= insertPosition);
2495 insertPosition = newInsertPosition;
2498 if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
2499 targets.insert(insertPosition, list2.at(i));
2505
2506
2507void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
2509 Q_Q(
const QQuickDeliveryAgent);
2511 const auto grabbers = exclusiveGrabbers(event);
2512 hasFiltered.clear();
2513 for (
auto grabber : grabbers) {
2515 QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
2518 QQuickPointerHandler *handler =
static_cast<QQuickPointerHandler *>(grabber);
2519 receiver =
static_cast<QQuickPointerHandler *>(grabber)->parentItem();
2523 hasFiltered.clear();
2524 if (sendFilteredPointerEvent(event, receiver))
2526 localizePointerEvent(event, receiver);
2528 handler->handlePointerEvent(event);
2534 hasFiltered.clear();
2536 deliverMatchingPointsToItem(receiver,
true, event);
2540 for (
auto &point : event->points()) {
2541 auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
2542 if (Q_UNLIKELY(!epd)) {
2543 qWarning() <<
"point is not in activePoints" << point;
2546 QList<QPointer<QObject>> relevantPassiveGrabbers;
2547 for (
int i = 0; i < epd->passiveGrabbersContext.size(); ++i) {
2548 if (epd->passiveGrabbersContext.at(i).data() == q)
2549 relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
2551 if (!relevantPassiveGrabbers.isEmpty())
2552 deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
2555 if (event->type() == QEvent::TouchUpdate && !isTouchPadWithMouseEmulation(event->device())) {
2556 for (
const auto &[item, id, fromFinger] : hoverItems) {
2558 bool res = deliverHoverEventToItem(item, item->mapFromScene(point.scenePosition()), point.scenePosition(), point.sceneLastPosition(),
2559 point.globalPosition(), event->modifiers(), event->timestamp(), HoverChange::Set);
2561 Q_ASSERT(([
this, item = item.get(), res]{
2562 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
2563 return !res || it2->hoverId != 0;
2574 if (!allPointsGrabbed(event)) {
2575 QList<QQuickItem *> targetItems;
2576 for (
auto &point : event->points()) {
2579 if (point.state() == QEventPoint::Pressed || qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(point)))
2581 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point,
false,
false);
2582 if (targetItems.size()) {
2583 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2585 targetItems = targetItemsForPoint;
2588 for (QQuickItem *item : targetItems) {
2589 if (grabbers.contains(item))
2591 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2592 localizePointerEvent(event, item);
2593 itemPrivate->handlePointerEvent(event,
true);
2594 if (allPointsGrabbed(event))
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event,
bool handlersOnly)
2641 QList<QQuickItem *> targetItems;
2642 const bool isTouch = isTouchEvent(event);
2643 if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) {
2644 if (
auto point =
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) {
2654 if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint)))
2655 cancelTouchMouseSynthesis();
2657 qCWarning(lcTouchTarget) <<
"during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId <<
"is missing from" << event;
2660 for (
int i = 0; i < event->pointCount(); ++i) {
2661 auto &point = event->point(i);
2665 if (isTouch && point.state() == QEventPoint::Pressed)
2666 resetIfDoubleTapPrevented(point);
2667 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch);
2668 if (targetItems.size()) {
2669 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2671 targetItems = targetItemsForPoint;
2675 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
2677 for (
auto &item : safeTargetItems) {
2681 if (isSubsceneAgent)
2682 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
2684 hasFiltered.clear();
2685 if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
2686 if (event->isAccepted())
2688 skipDelivery.append(item);
2693 if (skipDelivery.contains(item))
2698 for (
int i = 0; i < event->pointCount(); ++i)
2699 event->point(i).setAccepted(
false);
2701 deliverMatchingPointsToItem(item,
false, event, handlersOnly);
2702 if (event->allPointsAccepted())
2703 handlersOnly =
true;
2709 return handlersOnly;
2713
2714
2715
2716
2717
2718
2719
2720void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item,
bool isGrabber, QPointerEvent *pointerEvent,
bool handlersOnly)
2722 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2723#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
2728 if (itemPrivate->wasDeleted)
2731 localizePointerEvent(pointerEvent, item);
2732 bool isMouse = isMouseEvent(pointerEvent);
2736 if (pointerEvent->type() != QEvent::MouseButtonDblClick)
2737 itemPrivate->handlePointerEvent(pointerEvent);
2744 if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent()
2745 && !exclusiveGrabbers(pointerEvent).contains(item))
2749 if (sendFilteredPointerEvent(pointerEvent, item))
2755 auto button =
static_cast<QSinglePointEvent *>(pointerEvent)->button();
2756 if ((isGrabber && button == Qt::NoButton) || item->acceptedMouseButtons().testFlag(button)) {
2759 auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0));
2760 pointerEvent->accept();
2761 if (isGrabber && sendFilteredPointerEvent(pointerEvent, item))
2763 localizePointerEvent(pointerEvent, item);
2764 QCoreApplication::sendEvent(item, pointerEvent);
2765 if (pointerEvent->isAccepted()) {
2766 auto &point = pointerEvent->point(0);
2767 auto mouseGrabber = pointerEvent->exclusiveGrabber(point);
2768 if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
2774 if (item != lastUngrabbed) {
2775 item->mouseUngrabEvent();
2776 lastUngrabbed = item;
2778 }
else if (item->isEnabled() && item->isVisible() && point.state() == QEventPoint::State::Pressed) {
2779 pointerEvent->setExclusiveGrabber(point, item);
2781 point.setAccepted(
true);
2787 if (!isTouchEvent(pointerEvent))
2790 bool eventAccepted =
false;
2791 QMutableTouchEvent touchEvent;
2792 itemPrivate->localizedTouchEvent(
static_cast<QTouchEvent *>(pointerEvent),
false, &touchEvent);
2793 if (touchEvent.type() == QEvent::None)
2796 if (item->acceptTouchEvents()) {
2797 qCDebug(lcTouch) <<
"considering delivering" << &touchEvent <<
" to " << item;
2800 qCDebug(lcTouch) <<
"actually delivering" << &touchEvent <<
" to " << item;
2801 QCoreApplication::sendEvent(item, &touchEvent);
2802 eventAccepted = touchEvent.isAccepted();
2805 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2806 !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
2807 deliverTouchAsMouse(item, &touchEvent);
2811 Q_ASSERT(item->acceptTouchEvents());
2812 if (eventAccepted) {
2813 bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
2814 for (
int i = 0; i < touchEvent.pointCount(); ++i) {
2815 auto &point = touchEvent.point(i);
2817 point.setAccepted();
2819 if (isPressOrRelease && !(itemPrivate->deliveryAgent() && pointerEvent->exclusiveGrabber(point)))
2820 pointerEvent->setExclusiveGrabber(point, item);
2825 for (
const auto &point: touchEvent.points()) {
2826 if (point.state() == QEventPoint::State::Pressed) {
2827 if (pointerEvent->exclusiveGrabber(point) == item) {
2828 qCDebug(lcTouchTarget) <<
"TP" << Qt::hex << point.id() <<
"disassociated";
2829 pointerEvent->setExclusiveGrabber(point,
nullptr);
2836#if QT_CONFIG(quick_draganddrop)
2837void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
2839 QObject *formerTarget = grabber->target();
2840 grabber->resetTarget();
2841 QQuickDragGrabber::iterator grabItem = grabber->begin();
2842 if (grabItem != grabber->end()) {
2843 Q_ASSERT(event->type() != QEvent::DragEnter);
2844 if (event->type() == QEvent::Drop) {
2845 QDropEvent *e =
static_cast<QDropEvent *>(event);
2846 for (e->setAccepted(
false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
2847 QPointF p = (**grabItem)->mapFromScene(e->position().toPoint());
2848 QDropEvent translatedEvent(
2850 e->possibleActions(),
2854 QQuickDropEventEx::copyActions(&translatedEvent, *e);
2855 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2856 e->setAccepted(translatedEvent.isAccepted());
2857 e->setDropAction(translatedEvent.dropAction());
2858 grabber->setTarget(**grabItem);
2861 if (event->type() != QEvent::DragMove) {
2862 QDragLeaveEvent leaveEvent;
2863 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2864 QCoreApplication::sendEvent(**grabItem, &leaveEvent);
2865 grabber->ignoreList().clear();
2868 QDragMoveEvent *moveEvent =
static_cast<QDragMoveEvent *>(event);
2872 QVarLengthArray<QQuickItem*, 64> currentGrabItems;
2873 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2874 currentGrabItems.append(**grabItem);
2877 QDragEnterEvent enterEvent(
2878 moveEvent->position(),
2879 moveEvent->possibleActions(),
2880 moveEvent->mimeData(),
2881 moveEvent->buttons(),
2882 moveEvent->modifiers());
2883 QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
2884 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, ¤tGrabItems,
2887 for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
2888 int i = currentGrabItems.indexOf(**grabItem);
2890 currentGrabItems.remove(i);
2892 QDragMoveEvent translatedEvent(
2893 (**grabItem)->mapFromScene(moveEvent->position()),
2894 moveEvent->possibleActions(),
2895 moveEvent->mimeData(),
2896 moveEvent->buttons(),
2897 moveEvent->modifiers());
2898 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
2899 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2900 event->setAccepted(translatedEvent.isAccepted());
2901 QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
2906 QDragLeaveEvent leaveEvent;
2907 for (QQuickItem *i : currentGrabItems)
2908 QCoreApplication::sendEvent(i, &leaveEvent);
2913 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
2914 QDragMoveEvent *e =
static_cast<QDragMoveEvent *>(event);
2915 QDragEnterEvent enterEvent(
2917 e->possibleActions(),
2921 QQuickDropEventEx::copyActions(&enterEvent, *e);
2922 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
2924 grabber->ignoreList().clear();
2928bool QQuickDeliveryAgentPrivate::deliverDragEvent(
2929 QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
2930 QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
2932 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2933 if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
2935 QPointF p = item->mapFromScene(event->position().toPoint());
2936 bool itemContained = item->contains(p);
2938 const int itemIndex = grabber->ignoreList().indexOf(item);
2939 if (!itemContained) {
2941 grabber->ignoreList().remove(itemIndex);
2943 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
2947 QDragEnterEvent enterEvent(
2949 event->possibleActions(),
2952 event->modifiers());
2953 QQuickDropEventEx::copyActions(&enterEvent, *event);
2954 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2957 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2958 if (children.at(ii)->z() < 0)
2960 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2964 if (itemContained) {
2967 if (currentGrabItems && currentGrabItems->contains(item)) {
2968 grabber->grab(item);
2969 grabber->setTarget(item);
2973 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
2974 if (event->type() == QEvent::DragEnter) {
2976 QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
2977 if (formerTargetItem && currentGrabItems) {
2978 QDragLeaveEvent leaveEvent;
2979 QCoreApplication::sendEvent(formerTarget, &leaveEvent);
2983 currentGrabItems->removeAll(formerTarget);
2985 }
else if (itemIndex >= 0) {
2990 QDragMoveEvent translatedEvent(p, event->possibleActions(), event->mimeData(),
2991 event->buttons(), event->modifiers(), event->type());
2992 QQuickDropEventEx::copyActions(&translatedEvent, *event);
2993 translatedEvent.setAccepted(event->isAccepted());
2994 QCoreApplication::sendEvent(item, &translatedEvent);
2995 event->setAccepted(translatedEvent.isAccepted());
2996 event->setDropAction(translatedEvent.dropAction());
2997 if (event->type() == QEvent::DragEnter) {
2998 if (translatedEvent.isAccepted()) {
2999 grabber->grab(item);
3000 grabber->setTarget(item);
3002 }
else if (itemIndex < 0) {
3003 grabber->ignoreList().append(item);
3012 for (
int ii = children.size() - 1; ii >= 0; --ii) {
3013 if (children.at(ii)->z() >= 0)
3015 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
3024
3025
3026
3027
3028
3029
3030
3031bool QQuickDeliveryAgentPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3033 return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
3037
3038
3039bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3041 if (!allowChildEventFiltering)
3043 if (!filteringParent)
3045 bool filtered =
false;
3046 const bool hasHandlers = QQuickItemPrivate::get(receiver)->hasPointerHandlers();
3047 if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
3048 hasFiltered.append(filteringParent);
3049 if (isMouseEvent(event)) {
3050 if (receiver->acceptedMouseButtons()) {
3051 const bool wasAccepted = event->allPointsAccepted();
3052 Q_ASSERT(event->pointCount());
3053 localizePointerEvent(event, receiver);
3054 event->setAccepted(
true);
3055 auto oldMouseGrabber = event->exclusiveGrabber(event->point(0));
3056 if (filteringParent->childMouseEventFilter(receiver, event)) {
3057 qCDebug(lcMouse) <<
"mouse event intercepted by childMouseEventFilter of " << filteringParent;
3058 skipDelivery.append(filteringParent);
3060 if (event->isAccepted() && event->isBeginEvent()) {
3061 auto &point = event->point(0);
3062 auto mouseGrabber = event->exclusiveGrabber(point);
3063 if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
3064 receiver->mouseUngrabEvent();
3066 event->setExclusiveGrabber(point, receiver);
3071 event->setAccepted(wasAccepted);
3074 }
else if (isTouchEvent(event)) {
3075 const bool acceptsTouchEvents = receiver->acceptTouchEvents() || hasHandlers;
3076 auto device = event->device();
3077 if (isTouchPadWithMouseEmulation(event->device())) {
3078 qCDebug(lcTouchTarget) <<
"skipping filtering of synth-mouse event from" << device;
3079 }
else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
3082 QMutableTouchEvent filteringParentTouchEvent;
3083 QQuickItemPrivate::get(receiver)->localizedTouchEvent(
static_cast<QTouchEvent *>(event),
true, &filteringParentTouchEvent);
3084 if (filteringParentTouchEvent.type() != QEvent::None) {
3085 qCDebug(lcTouch) <<
"letting parent" << filteringParent <<
"filter for" << receiver << &filteringParentTouchEvent;
3086 filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent);
3088 qCDebug(lcTouch) <<
"touch event intercepted by childMouseEventFilter of " << filteringParent;
3089 event->setAccepted(filteringParentTouchEvent.isAccepted());
3090 skipDelivery.append(filteringParent);
3091 if (event->isAccepted()) {
3092 for (
auto point : filteringParentTouchEvent.points()) {
3093 const QQuickItem *exclusiveGrabber = qobject_cast<
const QQuickItem *>(event->exclusiveGrabber(point));
3103 const bool grabberInsideFilteringParent = exclusiveGrabber &&
3104 exclusiveGrabber->acceptTouchEvents() &&
3105 filteringParent->isAncestorOf(
const_cast<QQuickItem *>(exclusiveGrabber));
3106 if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab() || grabberInsideFilteringParent)
3107 event->setExclusiveGrabber(point, filteringParent);
3115 for (
int i = 0; i < event->pointCount(); ++i)
3116 event->point(i).setAccepted(
false);
3118 }
else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
3119 !filteringParent->acceptTouchEvents()) {
3120 qCDebug(lcTouch) <<
"touch event NOT intercepted by childMouseEventFilter of " << filteringParent
3121 <<
"; accepts touch?" << filteringParent->acceptTouchEvents()
3122 <<
"receiver accepts touch?" << acceptsTouchEvents
3123 <<
"so, letting parent filter a synth-mouse event";
3125 for (
auto &tp : filteringParentTouchEvent.points()) {
3127 switch (tp.state()) {
3128 case QEventPoint::State::Pressed:
3129 t = QEvent::MouseButtonPress;
3131 case QEventPoint::State::Released:
3132 t = QEvent::MouseButtonRelease;
3134 case QEventPoint::State::Stationary:
3137 t = QEvent::MouseMove;
3141 bool touchMouseUnset = (touchMouseId == -1);
3143 if (touchMouseUnset || touchMouseId == tp.id()) {
3146 QMutableSinglePointEvent mouseEvent;
3147 touchToMouseEvent(t, tp, &filteringParentTouchEvent, &mouseEvent);
3151 touchMouseId = tp.id();
3152 touchMouseDevice = event->pointingDevice();
3153 filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent);
3155 qCDebug(lcTouch) <<
"touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
3156 event->setAccepted(mouseEvent.isAccepted());
3157 skipDelivery.append(filteringParent);
3158 if (event->isAccepted() && event->isBeginEvent()) {
3159 qCDebug(lcTouchTarget) <<
"TP (mouse)" << Qt::hex << tp.id() <<
"->" << filteringParent;
3160 filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent);
3161 touchMouseUnset =
false;
3162 filteringParent->grabMouse();
3165 if (touchMouseUnset)
3168 cancelTouchMouseSynthesis();
3169 mouseEvent.point(0).setAccepted(
false);
3180 return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194bool QQuickDeliveryAgentPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3196 if (!filteringParent)
3199 QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
3200 if (filteringParentPrivate->replayingPressEvent)
3203 bool filtered =
false;
3204 if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
3205 hasFiltered.append(filteringParent);
3206 if (filteringParent->childMouseEventFilter(receiver, event)) {
3208 skipDelivery.append(filteringParent);
3210 qCDebug(lcMouseTarget) <<
"for" << receiver << filteringParent <<
"childMouseEventFilter ->" << filtered;
3213 return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
3217
3218
3219
3220
3221
3222
3223bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event,
int startDragThreshold)
3225 QStyleHints *styleHints = QGuiApplication::styleHints();
3226 bool dragVelocityLimitAvailable = event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
3227 && styleHints->startDragVelocity();
3228 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3229 if (dragVelocityLimitAvailable) {
3230 QVector2D velocityVec = event->point(0).velocity();
3231 qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
3232 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3234 return overThreshold;
3238
3239
3240
3241
3242
3243
3244bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const QEventPoint &tp,
int startDragThreshold)
3246 QStyleHints *styleHints = qApp->styleHints();
3247 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3248 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
3249 if (!overThreshold && dragVelocityLimitAvailable) {
3250 qreal velocity = axis == Qt::XAxis ? tp.velocity().x() : tp.velocity().y();
3251 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3253 return overThreshold;
3257
3258
3259
3260
3261bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
3263 int threshold = qApp->styleHints()->startDragDistance();
3264 return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
3268
3269
3270
3271
3272
3273
3274QList<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item,
const QContextMenuEvent *event)
const
3276 auto predicate = [](QQuickItem *,
const QEvent *) -> std::optional<
bool> {
3277 return std::nullopt;
3280 const auto pos = event->pos().isNull() ? activeFocusItem->mapToScene({}).toPoint() : event->pos();
3281 if (event->pos().isNull())
3282 qCDebug(lcContextMenu) <<
"for QContextMenuEvent, active focus item is" << activeFocusItem <<
"@" << pos;
3283 return eventTargets(item, event, -1, pos, pos, predicate);
3287
3288
3289
3290
3291void QQuickDeliveryAgentPrivate::deliverContextMenuEvent(QContextMenuEvent *event)
3293 skipDelivery.clear();
3294 QList<QQuickItem *> targetItems = contextMenuTargets(rootItem, event);
3295 qCDebug(lcContextMenu) <<
"delivering context menu event" << event <<
"to" << targetItems.size() <<
"target item(s)";
3296 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
3297 for (
auto &item : safeTargetItems) {
3298 qCDebug(lcContextMenu) <<
"- attempting to deliver to" << item;
3302 if (isSubsceneAgent)
3303 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
3305 QCoreApplication::sendEvent(item, event);
3306 if (event->isAccepted())
3311#ifndef QT_NO_DEBUG_STREAM
3314 QDebugStateSaver saver(debug);
3317 debug <<
"QQuickDeliveryAgent(0)";
3321 debug <<
"QQuickDeliveryAgent(";
3322 if (!da->objectName().isEmpty())
3323 debug << da->objectName() <<
' ';
3324 auto root = da->rootItem();
3325 if (Q_LIKELY(root)) {
3326 debug <<
"root=" << root->metaObject()->className();
3327 if (!root->objectName().isEmpty())
3328 debug <<
' ' << root->objectName();
3339#include "moc_qquickdeliveryagent_p.cpp"
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static bool isEndOfFingerTouchSequence(const QTouchEvent *event)
static void markHovered(QQuickDeliveryAgentPrivate::HoverItemState &state, uint hoverId, bool fromTouch)
static QQuickDeliveryAgentPrivate::HoverItems::iterator findHoverStateByItem(QQuickDeliveryAgentPrivate::HoverItems &hoverItems, QQuickItem *item)
static QQuickDeliveryAgentPrivate::HoverItems::const_iterator findHoverStateByItem(const QQuickDeliveryAgentPrivate::HoverItems &hoverItems, const QQuickItem *item)
static bool allowSyntheticRightClick()
static bool windowHasFocus(QQuickWindow *win)
static QQuickItem * findFurthestFocusScopeAncestor(QQuickItem *item)
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)