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 (device->type() == QInputDevice::DeviceType::TouchPad && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
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:
1744QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(
const QInputDevice *device)
1746 QInputDevicePrivate *devPriv = QInputDevicePrivate::get(
const_cast<QInputDevice *>(device));
1747 if (devPriv->qqExtra)
1748 return static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1749 auto extra =
new QQuickPointingDeviceExtra;
1750 devPriv->qqExtra = extra;
1751 QObject::connect(device, &QObject::destroyed, device, [devPriv]() {
1752 delete static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1753 devPriv->qqExtra =
nullptr;
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
1786 if (isSubsceneAgent)
1789 QEventPoint::States states = event->touchPointStates();
1790 if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
1791 qCDebug(lcTouchCmprs) <<
"no compression" << event;
1796 if (!delayedTouch) {
1797 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points()));
1798 delayedTouch->setTimestamp(event->timestamp());
1799 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1800 auto &tp = delayedTouch->point(i);
1801 QMutableEventPoint::detach(tp);
1803 ++compressedTouchCount;
1804 qCDebug(lcTouchCmprs) <<
"delayed" << compressedTouchCount << delayedTouch.get();
1805 if (QQuickWindow *window = rootItem->window())
1806 window->maybeUpdate();
1811 if (delayedTouch->type() == event->type() &&
1812 delayedTouch->device() == event->device() &&
1813 delayedTouch->modifiers() == event->modifiers() &&
1814 delayedTouch->pointCount() == event->pointCount())
1817 bool mismatch =
false;
1819 auto tpts = event->points();
1820 for (qsizetype i = 0; i < event->pointCount(); ++i) {
1821 const auto &tp = tpts.at(i);
1822 const auto &tpDelayed = delayedTouch->point(i);
1823 if (tp.id() != tpDelayed.id()) {
1828 if (tpDelayed.state() == QEventPoint::State::Updated && tp.state() == QEventPoint::State::Stationary)
1829 QMutableEventPoint::setState(tpts[i], QEventPoint::State::Updated);
1836 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts));
1837 delayedTouch->setTimestamp(event->timestamp());
1838 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1839 auto &tp = delayedTouch->point(i);
1840 QMutableEventPoint::detach(tp);
1842 ++compressedTouchCount;
1843 qCDebug(lcTouchCmprs) <<
"coalesced" << compressedTouchCount << delayedTouch.get();
1844 if (QQuickWindow *window = rootItem->window())
1845 window->maybeUpdate();
1851 deliverDelayedTouchEvent();
1852 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(),
1853 event->modifiers(), event->points()));
1854 delayedTouch->setTimestamp(event->timestamp());
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1871 if (!event->isEndEvent())
1873 if (!event->pointCount())
1876 if (Q_UNLIKELY(event->pointerType() != QPointingDevice::PointerType::Finger))
1881 const auto *devPriv = QPointingDevicePrivate::get(event->pointingDevice());
1882 for (
const auto &activePoint : devPriv->activePoints) {
1883 if (activePoint.second.eventPoint.state() != QEventPoint::State::Released)
1893void QQuickDeliveryAgentPrivate::handleTouchEvent(QTouchEvent *event)
1895 Q_Q(QQuickDeliveryAgent);
1896 translateTouchEvent(event);
1898 if (event->pointCount()) {
1899 auto &point = event->point(0);
1900 if (point.state() == QEventPoint::State::Released) {
1904 lastMousePosition = QPointF();
1905 lastMousePositionFromTouch =
false;
1907 lastMousePosition = point.position();
1908 lastMousePositionFromTouch =
1909 event->pointerType() == QPointingDevice::PointerType::Finger;
1916 const bool fingerHoverEnded = isEndOfFingerTouchSequence(event);
1918 qCDebug(lcTouch) << q << event;
1920 static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet(
"QML_NO_TOUCH_COMPRESSION");
1922 if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) {
1923 deliverPointerEvent(event);
1924 }
else if (!compressTouchEvent(event)) {
1926 deliverDelayedTouchEvent();
1927 qCDebug(lcTouchCmprs) <<
"resuming delivery" << event;
1929 deliverPointerEvent(event);
1934 if (fingerHoverEnded)
1935 clearTouchHover(event->timestamp());
1939
1940
1941void QQuickDeliveryAgentPrivate::handleMouseEvent(QMouseEvent *event)
1943 Q_Q(QQuickDeliveryAgent);
1947 if (event->source() == Qt::MouseEventSynthesizedBySystem &&
1948 !(event->button() == Qt::RightButton && allowSyntheticRightClick())) {
1952 qCDebug(lcMouse) << q << event;
1954 switch (event->type()) {
1955 case QEvent::MouseButtonPress:
1956 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
1958 deliverPointerEvent(event);
1960 case QEvent::MouseButtonRelease:
1961 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
1963 deliverPointerEvent(event);
1964#if QT_CONFIG(cursor)
1965 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1968 case QEvent::MouseButtonDblClick:
1969 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1970 event->button(), event->buttons());
1971 deliverPointerEvent(event);
1973 case QEvent::MouseMove: {
1974 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
1975 event->position().x(), event->position().y());
1977 const QPointF last = lastMousePosition.isNull() ? event->scenePosition() : lastMousePosition;
1978 lastMousePosition = event->scenePosition();
1981 lastMousePositionFromTouch =
false;
1982 qCDebug(lcHoverTrace) << q <<
"mouse pos" << last <<
"->" << lastMousePosition;
1983 if (!event->points().size() || !event->exclusiveGrabber(event->point(0))) {
1984 bool accepted = deliverHoverEvent(event->scenePosition(), last, event->modifiers(), event->timestamp());
1985 event->setAccepted(accepted);
1987 deliverPointerEvent(event);
1988#if QT_CONFIG(cursor)
1990 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015void QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents(QQuickWindow *win)
2017 Q_Q(QQuickDeliveryAgent);
2018 QQuickDeliveryAgent *deliveringAgent = QQuickDeliveryAgentPrivate::currentEventDeliveryAgent;
2019 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = q;
2022 deliverDelayedTouchEvent();
2026 QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
2027 if (ut && ut->hasStartAnimationPending())
2028 ut->startAnimations();
2033#if !defined(Q_OS_WEBOS)
2043 if (frameSynchronousHoverInterval >= 0) {
2044 const bool timerActive = frameSynchronousHoverInterval > 0;
2045 const bool timerMature = frameSynchronousHoverTimer.elapsed() >= frameSynchronousHoverInterval;
2046 if (timerActive && !timerMature) {
2047 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery delayed: elapsed"
2048 << frameSynchronousHoverTimer.elapsed() <<
"<" << frameSynchronousHoverInterval;
2049 if (!frameSynchronousDelayTimer.isActive())
2050 frameSynchronousDelayTimer.start(frameSynchronousHoverInterval - frameSynchronousHoverTimer.elapsed(), q);
2051 }
else if (!win->mouseGrabberItem() && !lastMousePosition.isNull() &&
2052 (timerMature || QQuickWindowPrivate::get(win)->dirtyItemList)) {
2053 frameSynchronousDelayTimer.stop();
2054 qCDebug(lcHoverTrace) << q <<
"delivering frame-sync hover to root @" << lastMousePosition
2055 <<
"after elapsed time" << frameSynchronousHoverTimer.elapsed();
2056 if (deliverHoverEvent(lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0)) {
2057#if QT_CONFIG(cursor)
2058 QQuickWindowPrivate::get(rootItem->window())->updateCursor(
2059 sceneTransform ? sceneTransform->map(lastMousePosition) : lastMousePosition, rootItem);
2064 frameSynchronousHoverTimer.restart();
2065 ++frameSynchronousHover_counter;
2066 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery done: round" << frameSynchronousHover_counter;
2072 if (Q_UNLIKELY(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent &&
2073 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent != q))
2074 qCWarning(lcPtr,
"detected interleaved frame-sync and actual events");
2075 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveringAgent;
2079
2080
2081
2082
2083
2084
2085
2086void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition,
2087 const QPointerEvent *event,
const QEventPoint &point)
2089 Q_Q(QQuickDeliveryAgent);
2090 const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
2091 transition == QPointingDevice::GrabTransition::GrabPassive);
2094 if (
auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
2095 if (handler->parentItem()) {
2096 auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
2097 if (itemPriv->deliveryAgent() == q) {
2099 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
2100 const_cast<QEventPoint &>(point));
2105 QEventPoint lostPoint(point);
2106 QMutableEventPoint::setPosition(lostPoint, handler->parentItem()->mapFromScene(point.scenePosition()));
2107 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
2109 qCDebug(lcPtrLoc) << event->type() <<
"@" << point.scenePosition()
2110 <<
"to old handler" << grabber <<
"->" << lostPoint;
2116 if (isSubsceneAgent && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
2117 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
2119 }
else if (!isSubsceneAgent) {
2120 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
2121 const_cast<QEventPoint &>(point));
2123 }
else if (
auto *grabberItem = qmlobject_cast<QQuickItem *>(grabber)) {
2124 switch (transition) {
2125 case QPointingDevice::CancelGrabExclusive:
2126 case QPointingDevice::UngrabExclusive:
2127 if (isDeliveringTouchAsMouse() || isSinglePointDevice(point.device())) {
2130 QMutableSinglePointEvent e(QEvent::UngrabMouse, point.device(), point);
2131 hasFiltered.clear();
2132 if (!sendFilteredMouseEvent(&e, grabberItem, grabberItem->parentItem())) {
2133 lastUngrabbed = grabberItem;
2134 grabberItem->mouseUngrabEvent();
2139 bool allReleasedOrCancelled =
true;
2140 if (transition == QPointingDevice::UngrabExclusive && event) {
2141 for (
const auto &pt : event->points()) {
2142 if (pt.state() != QEventPoint::State::Released) {
2143 allReleasedOrCancelled =
false;
2148 if (allReleasedOrCancelled)
2149 grabberItem->touchUngrabEvent();
2155 auto *itemPriv = QQuickItemPrivate::get(grabberItem);
2158 if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
2159 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
2162 if (currentEventDeliveryAgent == q && event && event->device()) {
2163 switch (transition) {
2164 case QPointingDevice::GrabPassive: {
2165 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2167 QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q);
2168 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2170 case QPointingDevice::GrabExclusive: {
2171 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2173 epd->exclusiveGrabberContext = q;
2174 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2176 case QPointingDevice::CancelGrabExclusive:
2177 case QPointingDevice::UngrabExclusive:
2180 case QPointingDevice::UngrabPassive:
2181 case QPointingDevice::CancelGrabPassive:
2184 case QPointingDevice::OverrideGrabPassive:
2192
2193
2194
2195
2196
2197
2198
2199
2200void QQuickDeliveryAgentPrivate::ensureDeviceConnected(
const QPointingDevice *dev)
2202 Q_Q(QQuickDeliveryAgent);
2203 if (knownPointingDevices.contains(dev))
2205 knownPointingDevices.append(dev);
2206 connect(dev, &QPointingDevice::grabChanged,
this, &QQuickDeliveryAgentPrivate::onGrabChanged);
2207 QObject::connect(dev, &QObject::destroyed, q, [
this, dev] {
this->knownPointingDevices.removeAll(dev);});
2211
2212
2213
2214
2215
2216
2217void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
2219 Q_Q(QQuickDeliveryAgent);
2220 if (isTabletEvent(event))
2221 qCDebug(lcTablet) << q << event;
2226 ++pointerEventRecursionGuard;
2227 eventsInDelivery.push(event);
2233 QVarLengthArray<QPointF, 16> originalScenePositions;
2234 if (sceneTransform) {
2235 originalScenePositions.resize(event->pointCount());
2236 for (
int i = 0; i < event->pointCount(); ++i) {
2237 auto &pt = event->point(i);
2238 originalScenePositions[i] = pt.scenePosition();
2239 QMutableEventPoint::setScenePosition(pt, sceneTransform->map(pt.scenePosition()));
2240 qCDebug(lcPtrLoc) << q << event->type() << pt.id() <<
"transformed scene pos" << pt.scenePosition();
2242 }
else if (isSubsceneAgent) {
2243 qCDebug(lcPtrLoc) << q << event->type() <<
"no scene transform set";
2246 skipDelivery.clear();
2247 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
2249 qCDebug(lcPtr) << q <<
"delivering with" << sceneTransform << event;
2251 qCDebug(lcPtr) << q <<
"delivering" << event;
2252 for (
int i = 0; i < event->pointCount(); ++i)
2253 event->point(i).setAccepted(
false);
2255 if (event->isBeginEvent()) {
2256 ensureDeviceConnected(event->pointingDevice());
2257 if (event->type() == QEvent::MouseButtonPress && rootItem->window()
2258 &&
static_cast<QSinglePointEvent *>(event)->button() == Qt::RightButton) {
2259 QQuickWindowPrivate::get(rootItem->window())->rmbContextMenuEventEnabled =
true;
2261 if (!deliverPressOrReleaseEvent(event))
2262 event->setAccepted(
false);
2265 auto isHoveringMoveEvent = [](QPointerEvent *event) ->
bool {
2266 if (event->type() == QEvent::MouseMove) {
2267 const auto *spe =
static_cast<
const QSinglePointEvent *>(event);
2268 if (spe->button() == Qt::NoButton && spe->buttons() == Qt::NoButton)
2275
2276
2277
2278
2279
2280
2281
2282
2283 if (!allUpdatedPointsAccepted(event) && !isHoveringMoveEvent(event))
2284 deliverUpdatedPoints(event);
2285 if (event->isEndEvent())
2286 deliverPressOrReleaseEvent(event,
true);
2290 if (isTouchEvent(event) && touchMouseId >= 0) {
2291 if (
static_cast<QTouchEvent *>(event)->touchPointStates() == QEventPoint::State::Released) {
2292 cancelTouchMouseSynthesis();
2294 auto touchMousePoint = event->pointById(touchMouseId);
2295 if (touchMousePoint && touchMousePoint->state() == QEventPoint::State::Released)
2296 cancelTouchMouseSynthesis();
2300 eventsInDelivery.pop();
2301 if (sceneTransform) {
2302 for (
int i = 0; i < event->pointCount(); ++i)
2303 QMutableEventPoint::setScenePosition(event->point(i), originalScenePositions.at(i));
2305 --pointerEventRecursionGuard;
2306 lastUngrabbed =
nullptr;
2310
2311
2312
2313
2314
2315
2316
2317
2318
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
2346QList<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
const QEvent *event,
int pointId,
2347 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate)
const
2349 QList<QQuickItem *> targets;
2350 eventTargetsAppend(item, event, pointId, localPos, scenePos, predicate, targets);
2355
2356
2357
2358
2359
2361void QQuickDeliveryAgentPrivate::eventTargetsAppend(QQuickItem *item,
const QEvent *event,
int pointId,
2362 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate,
2363 QList<QQuickItem *> &targets)
const
2365 auto itemPrivate = QQuickItemPrivate::get(item);
2370 if (item != rootItem && !itemPrivate->eventHandlingBounds().contains(localPos) &&
2371 itemPrivate->effectivelyClipsEventHandlingChildren()) {
2372 qCDebug(lcPtrLoc) <<
"skipping because" << localPos <<
"is outside rectangular bounds of" << item;
2378 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2383 Q_ASSERT(event->isPointerEvent());
2384 QPointerEvent *pev =
const_cast<QPointerEvent *>(
static_cast<
const QPointerEvent *>(event));
2385 QEventPoint *point = pev->pointById(pointId);
2387 QMutableEventPoint::setPosition(*point, localPos);
2389 const std::optional<
bool> override = predicate(item, event);
2390 const bool relevant = override.has_value() ? override.value()
2391 : item == rootItem || item->contains(localPos);
2396 bool selfEmitted = !relevant;
2397 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2398 QQuickItem *child = children.at(ii);
2399 if (!selfEmitted && child->z() < 0) {
2400 targets.append(item);
2404 auto childPrivate = QQuickItemPrivate::get(child);
2405 if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
2406 (childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
2409 QTransform childToParent;
2410 childPrivate->itemToParentTransform(&childToParent);
2411 const QPointF childLocalPos = childToParent.inverted().map(localPos);
2412 eventTargetsAppend(child, event, pointId, childLocalPos, scenePos, predicate, targets);
2417 targets.append(item);
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449QList<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *item,
const QPointerEvent *event,
const QEventPoint &point,
2450 bool checkMouseButtons,
bool checkAcceptsTouch)
const
2452 auto predicate = [point, checkMouseButtons, checkAcceptsTouch](QQuickItem *item,
const QEvent *ev) -> std::optional<
bool> {
2453 const QPointerEvent *event =
static_cast<
const QPointerEvent *>(ev);
2454 auto itemPrivate = QQuickItemPrivate::get(item);
2455 if (itemPrivate->hasPointerHandlers()) {
2456 if (itemPrivate->anyPointerHandlerWants(event, point))
2459 if (checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
2461 if (checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
2465 return std::nullopt;
2468 return eventTargets(item, event, point.id(), item->mapFromScene(point.scenePosition()), point.scenePosition(), predicate);
2472
2473
2474
2475QList<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(
const QList<QQuickItem *> &list1,
const QList<QQuickItem *> &list2)
const
2477 QList<QQuickItem *> targets = list1;
2481 int insertPosition = targets.size();
2482 for (
int i = list2.size() - 1; i >= 0; --i) {
2483 int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
2484 if (newInsertPosition >= 0) {
2485 Q_ASSERT(newInsertPosition <= insertPosition);
2486 insertPosition = newInsertPosition;
2489 if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
2490 targets.insert(insertPosition, list2.at(i));
2496
2497
2498void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
2500 Q_Q(
const QQuickDeliveryAgent);
2502 const auto grabbers = exclusiveGrabbers(event);
2503 hasFiltered.clear();
2504 for (
auto grabber : grabbers) {
2506 QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
2509 QQuickPointerHandler *handler =
static_cast<QQuickPointerHandler *>(grabber);
2510 receiver =
static_cast<QQuickPointerHandler *>(grabber)->parentItem();
2514 hasFiltered.clear();
2515 if (sendFilteredPointerEvent(event, receiver))
2517 localizePointerEvent(event, receiver);
2519 handler->handlePointerEvent(event);
2525 hasFiltered.clear();
2527 deliverMatchingPointsToItem(receiver,
true, event);
2531 for (
auto &point : event->points()) {
2532 auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
2533 if (Q_UNLIKELY(!epd)) {
2534 qWarning() <<
"point is not in activePoints" << point;
2537 QList<QPointer<QObject>> relevantPassiveGrabbers;
2538 for (
int i = 0; i < epd->passiveGrabbersContext.size(); ++i) {
2539 if (epd->passiveGrabbersContext.at(i).data() == q)
2540 relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
2542 if (!relevantPassiveGrabbers.isEmpty())
2543 deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
2546 if (event->type() == QEvent::TouchUpdate) {
2547 for (
const auto &[item, id, fromFinger] : hoverItems) {
2549 bool res = deliverHoverEventToItem(item, item->mapFromScene(point.scenePosition()), point.scenePosition(), point.sceneLastPosition(),
2550 point.globalPosition(), event->modifiers(), event->timestamp(), HoverChange::Set);
2552 Q_ASSERT(([
this, item = item.get(), res]{
2553 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
2554 return !res || it2->hoverId != 0;
2565 if (!allPointsGrabbed(event)) {
2566 QList<QQuickItem *> targetItems;
2567 for (
auto &point : event->points()) {
2570 if (point.state() == QEventPoint::Pressed || qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(point)))
2572 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point,
false,
false);
2573 if (targetItems.size()) {
2574 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2576 targetItems = targetItemsForPoint;
2579 for (QQuickItem *item : targetItems) {
2580 if (grabbers.contains(item))
2582 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2583 localizePointerEvent(event, item);
2584 itemPrivate->handlePointerEvent(event,
true);
2585 if (allPointsGrabbed(event))
2592
2593
2594
2595
2596
2597
2598
2599
2600
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
2630bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event,
bool handlersOnly)
2632 QList<QQuickItem *> targetItems;
2633 const bool isTouch = isTouchEvent(event);
2634 if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) {
2635 if (
auto point =
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) {
2645 if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint)))
2646 cancelTouchMouseSynthesis();
2648 qCWarning(lcTouchTarget) <<
"during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId <<
"is missing from" << event;
2651 for (
int i = 0; i < event->pointCount(); ++i) {
2652 auto &point = event->point(i);
2656 if (isTouch && point.state() == QEventPoint::Pressed)
2657 resetIfDoubleTapPrevented(point);
2658 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch);
2659 if (targetItems.size()) {
2660 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2662 targetItems = targetItemsForPoint;
2666 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
2668 for (
auto &item : safeTargetItems) {
2672 if (isSubsceneAgent)
2673 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
2675 hasFiltered.clear();
2676 if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
2677 if (event->isAccepted())
2679 skipDelivery.append(item);
2684 if (skipDelivery.contains(item))
2689 for (
int i = 0; i < event->pointCount(); ++i)
2690 event->point(i).setAccepted(
false);
2692 deliverMatchingPointsToItem(item,
false, event, handlersOnly);
2693 if (event->allPointsAccepted())
2694 handlersOnly =
true;
2700 return handlersOnly;
2704
2705
2706
2707
2708
2709
2710
2711void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item,
bool isGrabber, QPointerEvent *pointerEvent,
bool handlersOnly)
2713 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2714#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
2719 if (itemPrivate->wasDeleted)
2722 localizePointerEvent(pointerEvent, item);
2723 bool isMouse = isMouseEvent(pointerEvent);
2727 if (pointerEvent->type() != QEvent::MouseButtonDblClick)
2728 itemPrivate->handlePointerEvent(pointerEvent);
2735 if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent()
2736 && !exclusiveGrabbers(pointerEvent).contains(item))
2740 if (sendFilteredPointerEvent(pointerEvent, item))
2746 auto button =
static_cast<QSinglePointEvent *>(pointerEvent)->button();
2747 if ((isGrabber && button == Qt::NoButton) || item->acceptedMouseButtons().testFlag(button)) {
2750 auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0));
2751 pointerEvent->accept();
2752 if (isGrabber && sendFilteredPointerEvent(pointerEvent, item))
2754 localizePointerEvent(pointerEvent, item);
2755 QCoreApplication::sendEvent(item, pointerEvent);
2756 if (pointerEvent->isAccepted()) {
2757 auto &point = pointerEvent->point(0);
2758 auto mouseGrabber = pointerEvent->exclusiveGrabber(point);
2759 if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
2765 if (item != lastUngrabbed) {
2766 item->mouseUngrabEvent();
2767 lastUngrabbed = item;
2769 }
else if (item->isEnabled() && item->isVisible() && point.state() == QEventPoint::State::Pressed) {
2770 pointerEvent->setExclusiveGrabber(point, item);
2772 point.setAccepted(
true);
2778 if (!isTouchEvent(pointerEvent))
2781 bool eventAccepted =
false;
2782 QMutableTouchEvent touchEvent;
2783 itemPrivate->localizedTouchEvent(
static_cast<QTouchEvent *>(pointerEvent),
false, &touchEvent);
2784 if (touchEvent.type() == QEvent::None)
2787 if (item->acceptTouchEvents()) {
2788 qCDebug(lcTouch) <<
"considering delivering" << &touchEvent <<
" to " << item;
2791 qCDebug(lcTouch) <<
"actually delivering" << &touchEvent <<
" to " << item;
2792 QCoreApplication::sendEvent(item, &touchEvent);
2793 eventAccepted = touchEvent.isAccepted();
2796 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2797 !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
2798 deliverTouchAsMouse(item, &touchEvent);
2802 Q_ASSERT(item->acceptTouchEvents());
2803 if (eventAccepted) {
2804 bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
2805 for (
int i = 0; i < touchEvent.pointCount(); ++i) {
2806 auto &point = touchEvent.point(i);
2808 point.setAccepted();
2810 if (isPressOrRelease && !(itemPrivate->deliveryAgent() && pointerEvent->exclusiveGrabber(point)))
2811 pointerEvent->setExclusiveGrabber(point, item);
2816 for (
const auto &point: touchEvent.points()) {
2817 if (point.state() == QEventPoint::State::Pressed) {
2818 if (pointerEvent->exclusiveGrabber(point) == item) {
2819 qCDebug(lcTouchTarget) <<
"TP" << Qt::hex << point.id() <<
"disassociated";
2820 pointerEvent->setExclusiveGrabber(point,
nullptr);
2827#if QT_CONFIG(quick_draganddrop)
2828void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
2830 QObject *formerTarget = grabber->target();
2831 grabber->resetTarget();
2832 QQuickDragGrabber::iterator grabItem = grabber->begin();
2833 if (grabItem != grabber->end()) {
2834 Q_ASSERT(event->type() != QEvent::DragEnter);
2835 if (event->type() == QEvent::Drop) {
2836 QDropEvent *e =
static_cast<QDropEvent *>(event);
2837 for (e->setAccepted(
false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
2838 QPointF p = (**grabItem)->mapFromScene(e->position().toPoint());
2839 QDropEvent translatedEvent(
2841 e->possibleActions(),
2845 QQuickDropEventEx::copyActions(&translatedEvent, *e);
2846 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2847 e->setAccepted(translatedEvent.isAccepted());
2848 e->setDropAction(translatedEvent.dropAction());
2849 grabber->setTarget(**grabItem);
2852 if (event->type() != QEvent::DragMove) {
2853 QDragLeaveEvent leaveEvent;
2854 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2855 QCoreApplication::sendEvent(**grabItem, &leaveEvent);
2856 grabber->ignoreList().clear();
2859 QDragMoveEvent *moveEvent =
static_cast<QDragMoveEvent *>(event);
2863 QVarLengthArray<QQuickItem*, 64> currentGrabItems;
2864 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2865 currentGrabItems.append(**grabItem);
2868 QDragEnterEvent enterEvent(
2869 moveEvent->position(),
2870 moveEvent->possibleActions(),
2871 moveEvent->mimeData(),
2872 moveEvent->buttons(),
2873 moveEvent->modifiers());
2874 QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
2875 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, ¤tGrabItems,
2878 for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
2879 int i = currentGrabItems.indexOf(**grabItem);
2881 currentGrabItems.remove(i);
2883 QDragMoveEvent translatedEvent(
2884 (**grabItem)->mapFromScene(moveEvent->position()),
2885 moveEvent->possibleActions(),
2886 moveEvent->mimeData(),
2887 moveEvent->buttons(),
2888 moveEvent->modifiers());
2889 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
2890 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2891 event->setAccepted(translatedEvent.isAccepted());
2892 QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
2897 QDragLeaveEvent leaveEvent;
2898 for (QQuickItem *i : currentGrabItems)
2899 QCoreApplication::sendEvent(i, &leaveEvent);
2904 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
2905 QDragMoveEvent *e =
static_cast<QDragMoveEvent *>(event);
2906 QDragEnterEvent enterEvent(
2908 e->possibleActions(),
2912 QQuickDropEventEx::copyActions(&enterEvent, *e);
2913 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
2915 grabber->ignoreList().clear();
2919bool QQuickDeliveryAgentPrivate::deliverDragEvent(
2920 QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
2921 QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
2923 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2924 if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
2926 QPointF p = item->mapFromScene(event->position().toPoint());
2927 bool itemContained = item->contains(p);
2929 const int itemIndex = grabber->ignoreList().indexOf(item);
2930 if (!itemContained) {
2932 grabber->ignoreList().remove(itemIndex);
2934 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
2938 QDragEnterEvent enterEvent(
2940 event->possibleActions(),
2943 event->modifiers());
2944 QQuickDropEventEx::copyActions(&enterEvent, *event);
2945 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2948 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2949 if (children.at(ii)->z() < 0)
2951 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2955 if (itemContained) {
2958 if (currentGrabItems && currentGrabItems->contains(item)) {
2959 grabber->grab(item);
2960 grabber->setTarget(item);
2964 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
2965 if (event->type() == QEvent::DragEnter) {
2967 QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
2968 if (formerTargetItem && currentGrabItems) {
2969 QDragLeaveEvent leaveEvent;
2970 QCoreApplication::sendEvent(formerTarget, &leaveEvent);
2974 currentGrabItems->removeAll(formerTarget);
2976 }
else if (itemIndex >= 0) {
2981 QDragMoveEvent translatedEvent(p, event->possibleActions(), event->mimeData(),
2982 event->buttons(), event->modifiers(), event->type());
2983 QQuickDropEventEx::copyActions(&translatedEvent, *event);
2984 translatedEvent.setAccepted(event->isAccepted());
2985 QCoreApplication::sendEvent(item, &translatedEvent);
2986 event->setAccepted(translatedEvent.isAccepted());
2987 event->setDropAction(translatedEvent.dropAction());
2988 if (event->type() == QEvent::DragEnter) {
2989 if (translatedEvent.isAccepted()) {
2990 grabber->grab(item);
2991 grabber->setTarget(item);
2993 }
else if (itemIndex < 0) {
2994 grabber->ignoreList().append(item);
3003 for (
int ii = children.size() - 1; ii >= 0; --ii) {
3004 if (children.at(ii)->z() >= 0)
3006 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
3015
3016
3017
3018
3019
3020
3021
3022bool QQuickDeliveryAgentPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3024 return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
3028
3029
3030bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3032 if (!allowChildEventFiltering)
3034 if (!filteringParent)
3036 bool filtered =
false;
3037 const bool hasHandlers = QQuickItemPrivate::get(receiver)->hasPointerHandlers();
3038 if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
3039 hasFiltered.append(filteringParent);
3040 if (isMouseEvent(event)) {
3041 if (receiver->acceptedMouseButtons()) {
3042 const bool wasAccepted = event->allPointsAccepted();
3043 Q_ASSERT(event->pointCount());
3044 localizePointerEvent(event, receiver);
3045 event->setAccepted(
true);
3046 auto oldMouseGrabber = event->exclusiveGrabber(event->point(0));
3047 if (filteringParent->childMouseEventFilter(receiver, event)) {
3048 qCDebug(lcMouse) <<
"mouse event intercepted by childMouseEventFilter of " << filteringParent;
3049 skipDelivery.append(filteringParent);
3051 if (event->isAccepted() && event->isBeginEvent()) {
3052 auto &point = event->point(0);
3053 auto mouseGrabber = event->exclusiveGrabber(point);
3054 if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
3055 receiver->mouseUngrabEvent();
3057 event->setExclusiveGrabber(point, receiver);
3062 event->setAccepted(wasAccepted);
3065 }
else if (isTouchEvent(event)) {
3066 const bool acceptsTouchEvents = receiver->acceptTouchEvents() || hasHandlers;
3067 auto device = event->device();
3068 if (device->type() == QInputDevice::DeviceType::TouchPad &&
3069 device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
3070 qCDebug(lcTouchTarget) <<
"skipping filtering of synth-mouse event from" << device;
3071 }
else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
3074 QMutableTouchEvent filteringParentTouchEvent;
3075 QQuickItemPrivate::get(receiver)->localizedTouchEvent(
static_cast<QTouchEvent *>(event),
true, &filteringParentTouchEvent);
3076 if (filteringParentTouchEvent.type() != QEvent::None) {
3077 qCDebug(lcTouch) <<
"letting parent" << filteringParent <<
"filter for" << receiver << &filteringParentTouchEvent;
3078 filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent);
3080 qCDebug(lcTouch) <<
"touch event intercepted by childMouseEventFilter of " << filteringParent;
3081 event->setAccepted(filteringParentTouchEvent.isAccepted());
3082 skipDelivery.append(filteringParent);
3083 if (event->isAccepted()) {
3084 for (
auto point : filteringParentTouchEvent.points()) {
3085 const QQuickItem *exclusiveGrabber = qobject_cast<
const QQuickItem *>(event->exclusiveGrabber(point));
3095 const bool grabberInsideFilteringParent = exclusiveGrabber &&
3096 exclusiveGrabber->acceptTouchEvents() &&
3097 filteringParent->isAncestorOf(
const_cast<QQuickItem *>(exclusiveGrabber));
3098 if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab() || grabberInsideFilteringParent)
3099 event->setExclusiveGrabber(point, filteringParent);
3107 for (
int i = 0; i < event->pointCount(); ++i)
3108 event->point(i).setAccepted(
false);
3110 }
else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
3111 !filteringParent->acceptTouchEvents()) {
3112 qCDebug(lcTouch) <<
"touch event NOT intercepted by childMouseEventFilter of " << filteringParent
3113 <<
"; accepts touch?" << filteringParent->acceptTouchEvents()
3114 <<
"receiver accepts touch?" << acceptsTouchEvents
3115 <<
"so, letting parent filter a synth-mouse event";
3117 for (
auto &tp : filteringParentTouchEvent.points()) {
3119 switch (tp.state()) {
3120 case QEventPoint::State::Pressed:
3121 t = QEvent::MouseButtonPress;
3123 case QEventPoint::State::Released:
3124 t = QEvent::MouseButtonRelease;
3126 case QEventPoint::State::Stationary:
3129 t = QEvent::MouseMove;
3133 bool touchMouseUnset = (touchMouseId == -1);
3135 if (touchMouseUnset || touchMouseId == tp.id()) {
3138 QMutableSinglePointEvent mouseEvent;
3139 touchToMouseEvent(t, tp, &filteringParentTouchEvent, &mouseEvent);
3143 touchMouseId = tp.id();
3144 touchMouseDevice = event->pointingDevice();
3145 filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent);
3147 qCDebug(lcTouch) <<
"touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
3148 event->setAccepted(mouseEvent.isAccepted());
3149 skipDelivery.append(filteringParent);
3150 if (event->isAccepted() && event->isBeginEvent()) {
3151 qCDebug(lcTouchTarget) <<
"TP (mouse)" << Qt::hex << tp.id() <<
"->" << filteringParent;
3152 filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent);
3153 touchMouseUnset =
false;
3154 filteringParent->grabMouse();
3157 if (touchMouseUnset)
3160 cancelTouchMouseSynthesis();
3161 mouseEvent.point(0).setAccepted(
false);
3172 return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186bool QQuickDeliveryAgentPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3188 if (!filteringParent)
3191 QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
3192 if (filteringParentPrivate->replayingPressEvent)
3195 bool filtered =
false;
3196 if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
3197 hasFiltered.append(filteringParent);
3198 if (filteringParent->childMouseEventFilter(receiver, event)) {
3200 skipDelivery.append(filteringParent);
3202 qCDebug(lcMouseTarget) <<
"for" << receiver << filteringParent <<
"childMouseEventFilter ->" << filtered;
3205 return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
3209
3210
3211
3212
3213
3214
3215bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event,
int startDragThreshold)
3217 QStyleHints *styleHints = QGuiApplication::styleHints();
3218 bool dragVelocityLimitAvailable = event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
3219 && styleHints->startDragVelocity();
3220 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3221 if (dragVelocityLimitAvailable) {
3222 QVector2D velocityVec = event->point(0).velocity();
3223 qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
3224 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3226 return overThreshold;
3230
3231
3232
3233
3234
3235
3236bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const QEventPoint &tp,
int startDragThreshold)
3238 QStyleHints *styleHints = qApp->styleHints();
3239 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3240 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
3241 if (!overThreshold && dragVelocityLimitAvailable) {
3242 qreal velocity = axis == Qt::XAxis ? tp.velocity().x() : tp.velocity().y();
3243 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3245 return overThreshold;
3249
3250
3251
3252
3253bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
3255 int threshold = qApp->styleHints()->startDragDistance();
3256 return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
3260
3261
3262
3263
3264
3265
3266QList<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item,
const QContextMenuEvent *event)
const
3268 auto predicate = [](QQuickItem *,
const QEvent *) -> std::optional<
bool> {
3269 return std::nullopt;
3272 const auto pos = event->pos().isNull() ? activeFocusItem->mapToScene({}).toPoint() : event->pos();
3273 if (event->pos().isNull())
3274 qCDebug(lcContextMenu) <<
"for QContextMenuEvent, active focus item is" << activeFocusItem <<
"@" << pos;
3275 return eventTargets(item, event, -1, pos, pos, predicate);
3279
3280
3281
3282
3283void QQuickDeliveryAgentPrivate::deliverContextMenuEvent(QContextMenuEvent *event)
3285 skipDelivery.clear();
3286 QList<QQuickItem *> targetItems = contextMenuTargets(rootItem, event);
3287 qCDebug(lcContextMenu) <<
"delivering context menu event" << event <<
"to" << targetItems.size() <<
"target item(s)";
3288 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
3289 for (
auto &item : safeTargetItems) {
3290 qCDebug(lcContextMenu) <<
"- attempting to deliver to" << item;
3294 if (isSubsceneAgent)
3295 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
3297 QCoreApplication::sendEvent(item, event);
3298 if (event->isAccepted())
3303#ifndef QT_NO_DEBUG_STREAM
3306 QDebugStateSaver saver(debug);
3309 debug <<
"QQuickDeliveryAgent(0)";
3313 debug <<
"QQuickDeliveryAgent(";
3314 if (!da->objectName().isEmpty())
3315 debug << da->objectName() <<
' ';
3316 auto root = da->rootItem();
3317 if (Q_LIKELY(root)) {
3318 debug <<
"root=" << root->metaObject()->className();
3319 if (!root->objectName().isEmpty())
3320 debug <<
' ' << root->objectName();
3331#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)