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>
30Q_STATIC_LOGGING_CATEGORY(lcTouchCmprs,
"qt.quick.touch.compression")
31Q_LOGGING_CATEGORY(lcTouchTarget,
"qt.quick.touch.target")
32Q_LOGGING_CATEGORY(lcMouse,
"qt.quick.mouse")
33Q_STATIC_LOGGING_CATEGORY(lcMouseTarget,
"qt.quick.mouse.target")
34Q_STATIC_LOGGING_CATEGORY(lcTablet,
"qt.quick.tablet")
35Q_LOGGING_CATEGORY(lcPtr,
"qt.quick.pointer")
36Q_STATIC_LOGGING_CATEGORY(lcPtrLoc,
"qt.quick.pointer.localization")
37Q_STATIC_LOGGING_CATEGORY(lcWheelTarget,
"qt.quick.wheel.target")
38Q_LOGGING_CATEGORY(lcHoverTrace,
"qt.quick.hover.trace")
39Q_LOGGING_CATEGORY(lcHoverCursor,
"qt.quick.hover.cursor")
40Q_LOGGING_CATEGORY(lcFocus,
"qt.quick.focus")
41Q_STATIC_LOGGING_CATEGORY(lcContextMenu,
"qt.quick.contextmenu")
45bool QQuickDeliveryAgentPrivate::subsceneAgentsExist(
false);
46QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentEventDeliveryAgent(
nullptr);
50 static int allowRightClick = -1;
51 if (allowRightClick < 0) {
53 allowRightClick = qEnvironmentVariableIntValue(
"QT_QUICK_ALLOW_SYNTHETIC_RIGHT_CLICK", &ok);
57 return allowRightClick != 0;
62 return std::find_if(hoverItems.begin(), hoverItems.end(),
63 [item](
const QQuickDeliveryAgentPrivate::HoverItemState &hoverState) {
64 return hoverState.item == item;
70 return std::find_if(hoverItems.cbegin(), hoverItems.cend(),
71 [item](
const QQuickDeliveryAgentPrivate::HoverItemState &hoverState) {
72 return hoverState.item == item;
76void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type,
const QEventPoint &p,
const QTouchEvent *touchEvent, QMutableSinglePointEvent *mouseEvent)
78 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
79 QMutableSinglePointEvent ret(type, touchEvent->pointingDevice(), p,
80 (type == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton),
81 (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton),
82 touchEvent->modifiers(), Qt::MouseEventSynthesizedByQt);
83 ret.setAccepted(
true);
84 ret.setTimestamp(touchEvent->timestamp());
88 Q_ASSERT(mouseEvent->device() == touchEvent->device());
89 if (Q_UNLIKELY(mouseEvent->device()->type() == QInputDevice::DeviceType::Mouse))
90 qWarning() <<
"Unexpected: synthesized an indistinguishable mouse event" << mouseEvent;
94
95
96bool QQuickDeliveryAgentPrivate::isWithinDoubleClickInterval(ulong timeInterval)
98 return timeInterval <
static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
102
103
104bool QQuickDeliveryAgentPrivate::isWithinDoubleTapDistance(
const QPoint &distanceBetweenPresses)
106 auto square = [](qint64 v) {
return v * v; };
107 return square(distanceBetweenPresses.x()) + square(distanceBetweenPresses.y()) <
108 square(QGuiApplication::styleHints()->touchDoubleTapDistance());
111bool QQuickDeliveryAgentPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp,
const QPoint &newPressPos)
113 const bool doubleClicked = isDeliveringTouchAsMouse() &&
114 isWithinDoubleTapDistance(newPressPos - touchMousePressPos) &&
115 isWithinDoubleClickInterval(newPressEventTimestamp - touchMousePressTimestamp);
117 touchMousePressTimestamp = 0;
119 touchMousePressTimestamp = newPressEventTimestamp;
120 touchMousePressPos = newPressPos;
122 return doubleClicked;
125void QQuickDeliveryAgentPrivate::resetIfDoubleTapPrevented(
const QEventPoint &pressedPoint)
127 if (touchMousePressTimestamp > 0 &&
128 (!isWithinDoubleTapDistance(pressedPoint.globalPosition().toPoint() - touchMousePressPos) ||
129 !isWithinDoubleClickInterval(pressedPoint.timestamp() - touchMousePressTimestamp))) {
130 touchMousePressTimestamp = 0;
131 touchMousePressPos = QPoint();
136
137
138
139
140
141
142
143QPointerEvent *QQuickDeliveryAgentPrivate::eventInDelivery()
const
145 if (eventsInDelivery.isEmpty())
147 return eventsInDelivery.top();
151
152
153
154
155QPointingDevicePrivate::EventPointData *QQuickDeliveryAgentPrivate::mousePointData()
157 if (eventsInDelivery.isEmpty())
159 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(eventsInDelivery.top()->pointingDevice()));
160 return devPriv->pointById(isDeliveringTouchAsMouse() ? touchMouseId : 0);
163void QQuickDeliveryAgentPrivate::cancelTouchMouseSynthesis()
165 qCDebug(lcTouchTarget) <<
"id" << touchMouseId <<
"on" << touchMouseDevice;
167 touchMouseDevice =
nullptr;
170bool QQuickDeliveryAgentPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent)
172 Q_Q(QQuickDeliveryAgent);
173 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
174 auto device = pointerEvent->pointingDevice();
177 if (device->type() == QInputDevice::DeviceType::TouchPad && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
178 qCDebug(lcTouchTarget) << q <<
"skipping delivery of synth-mouse event from" << device;
183 QMutableTouchEvent event;
184 QQuickItemPrivate::get(item)->localizedTouchEvent(pointerEvent,
false, &event);
185 if (!event.points().size())
191 for (
auto &p : event.points()) {
193 if (touchMouseId == -1 && p.state() & QEventPoint::State::Pressed) {
194 QPointF pos = item->mapFromScene(p.scenePosition());
197 if (!item->contains(pos))
200 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << item;
201 QMutableSinglePointEvent mousePress;
202 touchToMouseEvent(QEvent::MouseButtonPress, p, &event, &mousePress);
205 QCoreApplication::sendEvent(item, &mousePress);
206 event.setAccepted(mousePress.isAccepted());
207 if (mousePress.isAccepted()) {
208 touchMouseDevice = device;
209 touchMouseId = p.id();
210 const auto &pt = mousePress.point(0);
211 if (!mousePress.exclusiveGrabber(pt))
212 mousePress.setExclusiveGrabber(pt, item);
214 if (checkIfDoubleTapped(event.timestamp(), p.globalPosition().toPoint())) {
217 QMutableSinglePointEvent mouseDoubleClick;
218 touchToMouseEvent(QEvent::MouseButtonDblClick, p, &event, &mouseDoubleClick);
219 QCoreApplication::sendEvent(item, &mouseDoubleClick);
220 event.setAccepted(mouseDoubleClick.isAccepted());
221 if (!mouseDoubleClick.isAccepted())
222 cancelTouchMouseSynthesis();
230 }
else if (touchMouseDevice == device && p.id() == touchMouseId) {
231 if (p.state() & QEventPoint::State::Updated) {
232 if (touchMousePressTimestamp != 0) {
233 if (!isWithinDoubleTapDistance(p.globalPosition().toPoint() - touchMousePressPos))
234 touchMousePressTimestamp = 0;
236 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
237 QMutableSinglePointEvent me;
238 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
239 QCoreApplication::sendEvent(item, &me);
240 event.setAccepted(me.isAccepted());
242 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << mouseGrabberItem;
243 return event.isAccepted();
248 QMutableSinglePointEvent me;
249 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
250 if (lastMousePosition.isNull())
251 lastMousePosition = me.scenePosition();
252 QPointF last = lastMousePosition;
253 lastMousePosition = me.scenePosition();
255 deliverHoverEvent(me.scenePosition(), last, me.modifiers(), me.timestamp());
258 }
else if (p.state() & QEventPoint::State::Released) {
260 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
261 QMutableSinglePointEvent me;
262 touchToMouseEvent(QEvent::MouseButtonRelease, p, &event, &me);
263 QCoreApplication::sendEvent(item, &me);
265 if (item->acceptHoverEvents() && p.globalPosition() != QGuiApplicationPrivate::lastCursorPosition) {
266 QPointF localMousePos(qInf(), qInf());
267 if (QWindow *w = item->window())
268 localMousePos = item->mapFromScene(w->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition));
269 QMouseEvent mm(QEvent::MouseMove, localMousePos, QGuiApplicationPrivate::lastCursorPosition,
270 Qt::NoButton, Qt::NoButton, event.modifiers());
271 QCoreApplication::sendEvent(item, &mm);
273 if (pointerEvent->exclusiveGrabber(p) == mouseGrabberItem)
274 pointerEvent->setExclusiveGrabber(p,
nullptr);
276 cancelTouchMouseSynthesis();
277 return me.isAccepted();
287
288
289
290
291
292
293
294
295void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber,
bool mouse,
bool touch,
bool cancel)
297 Q_Q(QQuickDeliveryAgent);
298 if (eventsInDelivery.isEmpty()) {
300 for (
auto dev : knownPointingDevices) {
301 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(dev));
302 devPriv->removeGrabber(grabber, cancel);
306 auto eventInDelivery = eventsInDelivery.top();
307 if (Q_LIKELY(mouse) && eventInDelivery) {
308 auto epd = mousePointData();
309 if (epd && epd->exclusiveGrabber == grabber && epd->exclusiveGrabberContext.data() == q) {
310 QQuickItem *oldGrabber = qobject_cast<QQuickItem *>(epd->exclusiveGrabber);
311 qCDebug(lcMouseTarget) <<
"removeGrabber" << oldGrabber <<
"-> null";
312 eventInDelivery->setExclusiveGrabber(epd->eventPoint,
nullptr);
315 if (Q_LIKELY(touch)) {
317 const auto touchDevices = QPointingDevice::devices();
318 for (
auto device : touchDevices) {
319 if (device->type() != QInputDevice::DeviceType::TouchScreen)
321 if (QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(
static_cast<
const QPointingDevice *>(device)))->
322 removeExclusiveGrabber(eventInDelivery, grabber))
326 grabber->touchUngrabEvent();
331
332
333
334
335
336
337
338
339
340
341
342void QQuickDeliveryAgentPrivate::clearGrabbers(QPointerEvent *pointerEvent)
344 if (pointerEvent->isEndEvent()
345 && !(isTabletEvent(pointerEvent)
346 && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
347 || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
348 if (pointerEvent->isSinglePointEvent()) {
349 if (
static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
350 auto &firstPt = pointerEvent->point(0);
351 pointerEvent->setExclusiveGrabber(firstPt,
nullptr);
352 pointerEvent->clearPassiveGrabbers(firstPt);
355 for (
auto &point : pointerEvent->points()) {
356 if (point.state() == QEventPoint::State::Released) {
357 pointerEvent->setExclusiveGrabber(point,
nullptr);
358 pointerEvent->clearPassiveGrabbers(point);
366
367
368
369
370void QQuickDeliveryAgentPrivate::translateTouchEvent(QTouchEvent *touchEvent)
372 for (qsizetype i = 0; i != touchEvent->pointCount(); ++i) {
373 auto &pt = touchEvent->point(i);
374 QMutableEventPoint::setScenePosition(pt, pt.position());
381 const QWindow *focusWindow = QGuiApplication::focusWindow();
382 if (!focusWindow || win == focusWindow)
384 return QQuickRenderControlPrivate::isFocusWindowFor(win, focusWindow);
389 QQuickItem *parentItem = item->parentItem();
391 if (parentItem && parentItem->flags() & QQuickItem::ItemIsFocusScope)
392 return findFurthestFocusScopeAncestor(parentItem);
399static inline bool singleWindowOnScreen(QQuickWindow *win)
401 const QWindowList windowList = QGuiApplication::allWindows();
402 for (
int i = 0; i < windowList.count(); i++) {
403 QWindow *ii = windowList.at(i);
406 if (ii->screen() == win->screen())
415
416
417
418
419void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item,
420 Qt::FocusReason reason, FocusOptions options)
422 Q_Q(QQuickDeliveryAgent);
424 Q_ASSERT(scope || item == rootItem);
426 qCDebug(lcFocus) << q <<
"focus" << item <<
"in scope" << scope;
428 qCDebug(lcFocus) <<
" scopeSubFocusItem:" << QQuickItemPrivate::get(scope)->subFocusItem;
430 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) :
nullptr;
431 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
433 QQuickItem *oldActiveFocusItem =
nullptr;
434 QQuickItem *currentActiveFocusItem = activeFocusItem;
435 QQuickItem *newActiveFocusItem =
nullptr;
436 bool sendFocusIn =
false;
438 lastFocusReason = reason;
440 QVarLengthArray<QQuickItem *, 20> changed;
443 if (item == rootItem || scopePrivate->activeFocus) {
444 oldActiveFocusItem = activeFocusItem;
445 if (item->isEnabled()) {
446 newActiveFocusItem = item;
447 while (newActiveFocusItem->isFocusScope()
448 && newActiveFocusItem->scopedFocusItem()
449 && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
450 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
453 newActiveFocusItem = scope;
456 if (oldActiveFocusItem) {
458 QGuiApplication::inputMethod()->commit();
461 activeFocusItem =
nullptr;
463 QQuickItem *afi = oldActiveFocusItem;
464 while (afi && afi != scope) {
465 if (QQuickItemPrivate::get(afi)->activeFocus) {
466 QQuickItemPrivate::get(afi)->activeFocus =
false;
469 afi = afi->parentItem();
474 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
475 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
476 if (oldSubFocusItem) {
477 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
479 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
480 changed << oldSubFocusItem;
483 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
true);
486 if (!(options & DontChangeFocusProperty)) {
487 if (item != rootItem || windowHasFocus(rootItem->window())
491 || singleWindowOnScreen(rootItem->window())
494 itemPrivate->focus =
true;
495 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
500 if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) {
501 activeFocusItem = newActiveFocusItem;
503 QQuickItemPrivate::get(newActiveFocusItem)->activeFocus =
true;
504 changed << newActiveFocusItem;
506 QQuickItem *afi = newActiveFocusItem->parentItem();
507 while (afi && afi != scope) {
508 if (afi->isFocusScope()) {
509 QQuickItemPrivate::get(afi)->activeFocus =
true;
512 afi = afi->parentItem();
514 updateFocusItemTransform();
520 if (oldActiveFocusItem) {
521 QFocusEvent event(QEvent::FocusOut, reason);
522 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
526 if (sendFocusIn && activeFocusItem == newActiveFocusItem) {
527 QFocusEvent event(QEvent::FocusIn, reason);
528 QCoreApplication::sendEvent(newActiveFocusItem, &event);
531 if (activeFocusItem != currentActiveFocusItem)
532 emit rootItem->window()->focusObjectChanged(activeFocusItem);
534 if (!changed.isEmpty())
535 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
536 if (isSubsceneAgent) {
537 auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent;
538 qCDebug(lcFocus) <<
" delegating setFocusInScope to" << da;
546 QQuickItem *ancestorFS = findFurthestFocusScopeAncestor(item);
547 if (ancestorFS != item)
548 options |= QQuickDeliveryAgentPrivate::DontChangeSubFocusItem;
549 QQuickWindowPrivate::get(rootItem->window())->deliveryAgentPrivate()->setFocusInScope(da->rootItem(), item, reason, options);
551 if (oldActiveFocusItem == activeFocusItem)
552 qCDebug(lcFocus) <<
" activeFocusItem remains" << activeFocusItem <<
"in" << q;
554 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
557void QQuickDeliveryAgentPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions options)
560 Q_ASSERT(scope || item == rootItem);
561 Q_Q(QQuickDeliveryAgent);
562 qCDebug(lcFocus) << q <<
"clear focus" << item <<
"in scope" << scope;
564 QQuickItemPrivate *scopePrivate =
nullptr;
566 scopePrivate = QQuickItemPrivate::get(scope);
567 if ( !scopePrivate->subFocusItem )
571 QQuickItem *currentActiveFocusItem = activeFocusItem;
572 QQuickItem *oldActiveFocusItem =
nullptr;
573 QQuickItem *newActiveFocusItem =
nullptr;
575 lastFocusReason = reason;
577 QVarLengthArray<QQuickItem *, 20> changed;
579 Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
582 if (item == rootItem || scopePrivate->activeFocus) {
583 oldActiveFocusItem = activeFocusItem;
584 newActiveFocusItem = scope;
587 QGuiApplication::inputMethod()->commit();
590 activeFocusItem =
nullptr;
592 if (oldActiveFocusItem) {
593 QQuickItem *afi = oldActiveFocusItem;
594 while (afi && afi != scope) {
595 if (QQuickItemPrivate::get(afi)->activeFocus) {
596 QQuickItemPrivate::get(afi)->activeFocus =
false;
599 afi = afi->parentItem();
604 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
605 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
606 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
607 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
609 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
610 changed << oldSubFocusItem;
613 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
false);
615 }
else if (!(options & DontChangeFocusProperty)) {
616 QQuickItemPrivate *priv = QQuickItemPrivate::get(item);
618 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
622 if (newActiveFocusItem) {
623 Q_ASSERT(newActiveFocusItem == scope);
624 activeFocusItem = scope;
625 updateFocusItemTransform();
630 if (oldActiveFocusItem) {
631 QFocusEvent event(QEvent::FocusOut, reason);
632 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
636 if (newActiveFocusItem && activeFocusItem == newActiveFocusItem) {
637 QFocusEvent event(QEvent::FocusIn, reason);
638 QCoreApplication::sendEvent(newActiveFocusItem, &event);
641 QQuickWindow *rootItemWindow = rootItem->window();
642 if (activeFocusItem != currentActiveFocusItem && rootItemWindow)
643 emit rootItemWindow->focusObjectChanged(activeFocusItem);
645 if (!changed.isEmpty())
646 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
647 if (isSubsceneAgent && rootItemWindow) {
648 auto da = QQuickWindowPrivate::get(rootItemWindow)->deliveryAgent;
649 qCDebug(lcFocus) <<
" delegating clearFocusInScope to" << da;
650 QQuickWindowPrivate::get(rootItemWindow)->deliveryAgentPrivate()->clearFocusInScope(da->rootItem(), item, reason, options);
652 if (oldActiveFocusItem == activeFocusItem)
653 qCDebug(lcFocus) <<
"activeFocusItem remains" << activeFocusItem <<
"in" << q;
655 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
658void QQuickDeliveryAgentPrivate::clearFocusObject()
660 if (activeFocusItem == rootItem)
663 clearFocusInScope(rootItem, QQuickItemPrivate::get(rootItem)->subFocusItem, Qt::OtherFocusReason);
666void QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(QQuickItem **items,
int remaining, Qt::FocusReason reason)
668 QPointer<QQuickItem> item(*items);
671 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
673 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
674 itemPrivate->notifiedFocus = itemPrivate->focus;
675 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
676 emit item->focusChanged(itemPrivate->focus);
679 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
680 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
681 itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged,
bool(itemPrivate->activeFocus));
682 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
683 emit item->activeFocusChanged(itemPrivate->activeFocus);
688 notifyFocusChangesRecur(items + 1, remaining - 1, reason);
691bool QQuickDeliveryAgentPrivate::clearHover(ulong timestamp)
693 if (hoverItems.isEmpty())
696 QQuickWindow *window = rootItem->window();
700 const auto globalPos = QGuiApplicationPrivate::lastCursorPosition;
701 const QPointF lastPos = window->mapFromGlobal(globalPos);
702 const auto modifiers = QGuiApplication::keyboardModifiers();
710 for (
auto it = hoverItems.cbegin(); it != hoverItems.cend(); ++it) {
711 if (QQuickItem *item = it->item) {
712 deliverHoverEventToItem(item, item->mapFromScene(lastPos), lastPos, lastPos,
713 globalPos, modifiers, timestamp, HoverChange::Clear);
714 Q_ASSERT(([
this, item]{
715 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
716 return it2 == hoverItems.cend() || it2->hoverId == 0;
724void QQuickDeliveryAgentPrivate::updateFocusItemTransform()
727 if (activeFocusItem && QGuiApplication::focusObject() == activeFocusItem) {
728 QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(activeFocusItem);
729 QGuiApplication::inputMethod()->setInputItemTransform(focusPrivate->itemToWindowTransform());
730 QGuiApplication::inputMethod()->setInputItemRectangle(QRectF(0, 0, focusPrivate->width, focusPrivate->height));
731 activeFocusItem->updateInputMethod(Qt::ImInputItemClipRectangle);
737
738
739
740QQuickItem *QQuickDeliveryAgentPrivate::focusTargetItem()
const
743 return activeFocusItem;
746 QQuickItem *targetItem = rootItem;
748 while (targetItem->isFocusScope()
749 && targetItem->scopedFocusItem()
750 && targetItem->scopedFocusItem()->isEnabled()) {
751 targetItem = targetItem->scopedFocusItem();
758
759
760
761
762
763QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(
const QQuickItem *item)
765 if (currentEventDeliveryAgent)
766 return currentEventDeliveryAgent;
768 return QQuickItemPrivate::get(
const_cast<QQuickItem *>(item))->deliveryAgent();
773
774
775
776
777QQuickDeliveryAgent::QQuickDeliveryAgent(QQuickItem *rootItem)
778 : QObject(*
new QQuickDeliveryAgentPrivate(rootItem), rootItem)
782QQuickDeliveryAgent::~QQuickDeliveryAgent()
786QQuickDeliveryAgent::Transform::~Transform()
791
792
793
794QQuickItem *QQuickDeliveryAgent::rootItem()
const
796 Q_D(
const QQuickDeliveryAgent);
801
802
803
804
805QQuickDeliveryAgent::Transform *QQuickDeliveryAgent::sceneTransform()
const
807 Q_D(
const QQuickDeliveryAgent);
808 return d->sceneTransform;
812
813
814
815
816void QQuickDeliveryAgent::setSceneTransform(QQuickDeliveryAgent::Transform *transform)
818 Q_D(QQuickDeliveryAgent);
819 if (d->sceneTransform == transform)
821 qCDebug(lcPtr) <<
this << d->sceneTransform <<
"->" << transform;
822 if (d->sceneTransform)
823 delete d->sceneTransform;
824 d->sceneTransform = transform;
828
829
830
831
832
833
834bool QQuickDeliveryAgent::event(QEvent *ev)
836 Q_D(QQuickDeliveryAgent);
837 d->currentEventDeliveryAgent =
this;
838 auto cleanup = qScopeGuard([d] { d->currentEventDeliveryAgent =
nullptr; });
840 switch (ev->type()) {
841 case QEvent::MouseButtonPress:
842 case QEvent::MouseButtonRelease:
843 case QEvent::MouseButtonDblClick:
844 case QEvent::MouseMove: {
845 QMouseEvent *me =
static_cast<QMouseEvent*>(ev);
846 d->handleMouseEvent(me);
849 case QEvent::HoverEnter:
850 case QEvent::HoverLeave:
851 case QEvent::HoverMove: {
852 QHoverEvent *he =
static_cast<QHoverEvent*>(ev);
853 bool accepted = d->deliverHoverEvent(he->scenePosition(),
854 he->points().first().sceneLastPosition(),
855 he->modifiers(), he->timestamp());
856 d->lastMousePosition = he->scenePosition();
857 he->setAccepted(accepted);
859 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(d->sceneTransform ?
860 d->sceneTransform->map(he->scenePosition()) : he->scenePosition(), d->rootItem);
864 case QEvent::TouchBegin:
865 case QEvent::TouchUpdate:
866 case QEvent::TouchEnd: {
867 QTouchEvent *touch =
static_cast<QTouchEvent*>(ev);
868 d->handleTouchEvent(touch);
869 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
876 case QEvent::TouchCancel:
878 return d->deliverTouchCancelEvent(
static_cast<QTouchEvent*>(ev));
880 case QEvent::Enter: {
883 QEnterEvent *enter =
static_cast<QEnterEvent*>(ev);
884 const auto scenePos = enter->scenePosition();
885 qCDebug(lcHoverTrace) <<
this <<
"sending hover event due to QEnterEvent" << enter;
886 bool accepted = d->deliverHoverEvent(scenePos,
887 enter->points().first().sceneLastPosition(),
888 enter->modifiers(), enter->timestamp());
889 d->lastMousePosition = scenePos;
891 Q_ASSERT(enter->scenePosition() == scenePos);
892 enter->setAccepted(accepted);
894 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(enter->scenePosition(), d->rootItem);
900 d->lastMousePosition = QPointF();
902#if QT_CONFIG(quick_draganddrop)
903 case QEvent::DragEnter:
904 case QEvent::DragLeave:
905 case QEvent::DragMove:
907 d->deliverDragEvent(d->dragGrabber, ev);
910 case QEvent::FocusAboutToChange:
912 if (d->activeFocusItem)
913 qGuiApp->inputMethod()->commit();
916#if QT_CONFIG(gestures)
917 case QEvent::NativeGesture:
918 d->deliverSinglePointEventUntilAccepted(
static_cast<QPointerEvent *>(ev));
921 case QEvent::ShortcutOverride:
922 d->deliverKeyEvent(
static_cast<QKeyEvent *>(ev));
924 case QEvent::InputMethod:
925 case QEvent::InputMethodQuery:
927 QQuickItem *target = d->focusTargetItem();
929 QCoreApplication::sendEvent(target, ev);
932#if QT_CONFIG(wheelevent)
933 case QEvent::Wheel: {
934 auto event =
static_cast<QWheelEvent *>(ev);
935 qCDebug(lcMouse) << event;
938 if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate)
942 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
943 event->angleDelta().x(), event->angleDelta().y());
944 d->deliverSinglePointEventUntilAccepted(event);
945 d->lastWheelEventAccepted = event->isAccepted();
949#if QT_CONFIG(tabletevent)
950 case QEvent::TabletPress:
951 case QEvent::TabletMove:
952 case QEvent::TabletRelease:
954 auto *tabletEvent =
static_cast<QTabletEvent *>(ev);
955 d->deliverPointerEvent(tabletEvent);
957 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(tabletEvent->scenePosition(), d->rootItem);
962#ifndef QT_NO_CONTEXTMENU
963 case QEvent::ContextMenu:
964 d->deliverContextMenuEvent(
static_cast<QContextMenuEvent *>(ev));
968 Q_ASSERT(
static_cast<QTimerEvent *>(ev)->timerId() == d->frameSynchronousDelayTimer.timerId());
969 d->frameSynchronousDelayTimer.stop();
970 d->flushFrameSynchronousEvents(d->rootItem->window());
979void QQuickDeliveryAgentPrivate::deliverKeyEvent(QKeyEvent *e)
981 if (activeFocusItem) {
982 const bool keyPress = (e->type() == QEvent::KeyPress);
984 case QEvent::KeyPress:
985 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(), e->modifiers());
987 case QEvent::KeyRelease:
988 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(), e->modifiers());
994 QQuickItem *item = activeFocusItem;
997 if (keyPress && e->spontaneous() ==
false)
998 qt_sendShortcutOverrideEvent(item, e->timestamp(),
999 e->key(), e->modifiers(), e->text(),
1000 e->isAutoRepeat(), e->count());
1003 Q_ASSERT(e->type() != QEvent::ShortcutOverride || !e->isAccepted());
1004 if (e->type() != QEvent::ShortcutOverride)
1006 QCoreApplication::sendEvent(item, e);
1007 }
while (!e->isAccepted() && (item = item->parentItem()));
1011QQuickDeliveryAgentPrivate::QQuickDeliveryAgentPrivate(QQuickItem *root) :
1015 isSubsceneAgent(!qmlobject_cast<QQuickRootItem *>(rootItem))
1017#if QT_CONFIG(quick_draganddrop)
1018 dragGrabber =
new QQuickDragGrabber;
1020 if (isSubsceneAgent)
1021 subsceneAgentsExist =
true;
1022 const auto interval = qEnvironmentVariableIntegerValue(
"QT_QUICK_FRAME_SYNCHRONOUS_HOVER_INTERVAL");
1023 if (interval.has_value()) {
1024 qCDebug(lcHoverTrace) <<
"frame-synchronous hover interval" << interval;
1025 frameSynchronousHoverInterval =
int(interval.value());
1027 if (frameSynchronousHoverInterval > 0)
1028 frameSynchronousHoverTimer.start();
1031QQuickDeliveryAgentPrivate::~QQuickDeliveryAgentPrivate()
1033#if QT_CONFIG(quick_draganddrop)
1035 dragGrabber =
nullptr;
1037 delete sceneTransform;
1041
1042
1043
1044
1045
1046
1047QPointerEvent *QQuickDeliveryAgentPrivate::clonePointerEvent(QPointerEvent *event, std::optional<QPointF> transformedLocalPos)
1049 QPointerEvent *ret = event->clone();
1050 QEventPoint &point = ret->point(0);
1051 QMutableEventPoint::detach(point);
1052 QMutableEventPoint::setTimestamp(point, event->timestamp());
1053 if (transformedLocalPos)
1054 QMutableEventPoint::setPosition(point, *transformedLocalPos);
1059void QQuickDeliveryAgentPrivate::deliverToPassiveGrabbers(
const QList<QPointer <QObject> > &passiveGrabbers,
1060 QPointerEvent *pointerEvent)
1062 const QList<QObject *> &eventDeliveryTargets =
1063 QQuickPointerHandlerPrivate::deviceDeliveryTargets(pointerEvent->device());
1064 QVarLengthArray<std::pair<QQuickItem *,
bool>, 4> sendFilteredPointerEventResult;
1065 hasFiltered.clear();
1066 for (QObject *grabberObject : passiveGrabbers) {
1068 if (Q_UNLIKELY(!grabberObject))
1071 if (QQuickPointerHandler *handler = qobject_cast<QQuickPointerHandler *>(grabberObject)) {
1072 if (handler && !eventDeliveryTargets.contains(handler)) {
1073 bool alreadyFiltered =
false;
1074 QQuickItem *par = handler->parentItem();
1077 auto it = std::find_if(sendFilteredPointerEventResult.begin(), sendFilteredPointerEventResult.end(),
1078 [par](
const std::pair<QQuickItem *,
bool> &pair) {
return pair.first == par; });
1079 if (it != sendFilteredPointerEventResult.end()) {
1082 alreadyFiltered = it->second;
1084 alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par);
1085 sendFilteredPointerEventResult << std::make_pair(par, alreadyFiltered);
1087 if (!alreadyFiltered) {
1089 localizePointerEvent(pointerEvent, par);
1090 handler->handlePointerEvent(pointerEvent);
1093 }
else if (QQuickItem *grabberItem =
static_cast<QQuickItem *>(grabberObject)) {
1095 if (QQuickItem *excGrabber =
static_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(pointerEvent->point(0)))) {
1096 if ((isMouseEvent(pointerEvent) && excGrabber->keepMouseGrab())
1097 || (isTouchEvent(pointerEvent) && excGrabber->keepTouchGrab())) {
1101 localizePointerEvent(pointerEvent, grabberItem);
1102 QCoreApplication::sendEvent(grabberItem, pointerEvent);
1103 pointerEvent->accept();
1108bool QQuickDeliveryAgentPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1109 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1110 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp)
1112 QHoverEvent hoverEvent(type, scenePos, globalPos, lastScenePos, modifiers);
1113 hoverEvent.setTimestamp(timestamp);
1114 hoverEvent.setAccepted(
true);
1115 QEventPoint &point = hoverEvent.point(0);
1116 QMutableEventPoint::setPosition(point, localPos);
1117 if (Q_LIKELY(item->window()))
1118 QMutableEventPoint::setGlobalLastPosition(point, item->window()->mapToGlobal(lastScenePos));
1120 hasFiltered.clear();
1121 if (sendFilteredMouseEvent(&hoverEvent, item, item->parentItem()))
1124 QCoreApplication::sendEvent(item, &hoverEvent);
1126 return hoverEvent.isAccepted();
1130
1131
1132
1133
1135bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
1136 const QPointF &scenePos,
const QPointF &lastScenePos,
1137 Qt::KeyboardModifiers modifiers, ulong timestamp)
1155 const bool subtreeHoverEnabled = QQuickItemPrivate::get(rootItem)->subtreeHoverEnabled;
1156 const bool itemsWasHovered = !hoverItems.isEmpty();
1158 if (!subtreeHoverEnabled && !itemsWasHovered)
1163 if (subtreeHoverEnabled) {
1164 hoveredLeafItemFound =
false;
1165 QQuickPointerHandlerPrivate::deviceDeliveryTargets(QPointingDevice::primaryPointingDevice()).clear();
1166 deliverHoverEventRecursive(rootItem, scenePos, scenePos, lastScenePos,
1167 rootItem->mapToGlobal(scenePos), modifiers, timestamp);
1171 for (
auto it = hoverItems.begin(); it != hoverItems.end();) {
1172 const auto &[item, hoverId] = *it;
1173 if (hoverId == currentHoverId) {
1180 if (item && hoverId != 0)
1181 deliverHoverEventToItem(item, item->mapFromScene(scenePos), scenePos, lastScenePos,
1182 QGuiApplicationPrivate::lastCursorPosition, modifiers, timestamp, HoverChange::Clear);
1183 it = hoverItems.erase(it);
1187 const bool itemsAreHovered = !hoverItems.isEmpty();
1188 return itemsWasHovered || itemsAreHovered;
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(QQuickItem *item,
1228 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
const QPointF &globalPos,
1229 Qt::KeyboardModifiers modifiers, ulong timestamp)
1231 const QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1232 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1233 const bool hadChildrenChanged = itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged;
1235 for (
int ii = children.size() - 1; ii >= 0; --ii) {
1239 if (!hadChildrenChanged && Q_UNLIKELY(itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged))
1241 QQuickItem *child = children.at(ii);
1242 const QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
1244 if (!child->isVisible() || childPrivate->culled)
1246 if (!childPrivate->subtreeHoverEnabled)
1249 QTransform childToParent;
1250 childPrivate->itemToParentTransform(&childToParent);
1251 const QPointF childLocalPos = childToParent.inverted().map(localPos);
1256 if (childPrivate->effectivelyClipsEventHandlingChildren() &&
1257 !childPrivate->eventHandlingBounds().contains(childLocalPos)) {
1258#ifdef QT_BUILD_INTERNAL
1259 ++QQuickItemPrivate::effectiveClippingSkips_counter;
1265 const bool accepted = deliverHoverEventRecursive(child, childLocalPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1270 if (hoveredLeafItemFound) {
1278 return deliverHoverEventToItem(item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp, HoverChange::Set);
1282
1283
1284
1285
1286
1287
1288
1289bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1290 QQuickItem *item,
const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1291 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp, HoverChange hoverChange)
1293 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1294 const bool isHovering = item->contains(localPos);
1295 auto hoverItemIterator = findHoverStateByItem(hoverItems, item);
1296 const bool wasHovering = hoverItemIterator != hoverItems.end() && hoverItemIterator->hoverId != 0;
1298 qCDebug(lcHoverTrace) <<
"item:" << item <<
"scene pos:" << scenePos <<
"localPos:" << localPos
1299 <<
"wasHovering:" << wasHovering <<
"isHovering:" << isHovering;
1301 bool accepted =
false;
1306 if (itemPrivate->hoverEnabled && isHovering && hoverChange == HoverChange::Set) {
1311 hoveredLeafItemFound =
true;
1312 if (hoverItemIterator != hoverItems.end())
1313 hoverItemIterator->hoverId = currentHoverId;
1315 hoverItems.append({item, currentHoverId});
1318 accepted = sendHoverEvent(QEvent::HoverMove, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1320 accepted = sendHoverEvent(QEvent::HoverEnter, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1321 }
else if (wasHovering) {
1323 hoverItemIterator->hoverId = 0;
1324 sendHoverEvent(QEvent::HoverLeave, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1327 if (!itemPrivate->hasPointerHandlers())
1337 if (hoverChange == HoverChange::Clear) {
1339 QHoverEvent hoverEvent(QEvent::HoverLeave, scenePos, globalPos, lastScenePos, modifiers);
1340 hoverEvent.setTimestamp(timestamp);
1342 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1343 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1344 if (!hh->isHovered())
1346 hoverEvent.setAccepted(
true);
1347 QCoreApplication::sendEvent(hh, &hoverEvent);
1351 QMouseEvent hoverEvent(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, Qt::NoButton, modifiers);
1352 hoverEvent.setTimestamp(timestamp);
1354 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1355 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1358 hoverEvent.setAccepted(
true);
1359 hh->handlePointerEvent(&hoverEvent);
1360 if (hh->isHovered()) {
1363 hoveredLeafItemFound =
true;
1364 hoverItemIterator = findHoverStateByItem(hoverItems, item);
1365 if (hoverItemIterator != hoverItems.end())
1366 hoverItemIterator->hoverId = currentHoverId;
1368 hoverItems.append({item, currentHoverId});
1369 if (hh->isBlocking()) {
1370 qCDebug(lcHoverTrace) <<
"skipping rest of hover delivery due to blocking" << hh;
1384bool QQuickDeliveryAgentPrivate::deliverSinglePointEventUntilAccepted(QPointerEvent *event)
1386 Q_ASSERT(event->points().size() == 1);
1387 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
1388 QEventPoint &point = event->point(0);
1389 QList<QQuickItem *> targetItems = pointerTargets(rootItem, event, point,
false,
false);
1390 point.setAccepted(
false);
1395 for (
const auto &passiveGrabber : event->passiveGrabbers(point)) {
1396 if (
auto *grabberItem = qobject_cast<QQuickItem *>(passiveGrabber)) {
1397 if (targetItems.contains(grabberItem))
1399 localizePointerEvent(event, grabberItem);
1400 QCoreApplication::sendEvent(grabberItem, event);
1407 for (QQuickItem *item : targetItems) {
1408 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1409 localizePointerEvent(event, item);
1411 itemPrivate->handlePointerEvent(event);
1412 if (point.isAccepted())
1415 QCoreApplication::sendEvent(item, event);
1416 if (event->isAccepted()) {
1417 qCDebug(lcWheelTarget) << event <<
"->" << item;
1425bool QQuickDeliveryAgentPrivate::deliverTouchCancelEvent(QTouchEvent *event)
1427 qCDebug(lcTouch) << event;
1432 const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(event->pointingDevice()))->
1433 sendTouchCancelEvent(event);
1435 cancelTouchMouseSynthesis();
1440void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent()
1445 std::unique_ptr<QTouchEvent> e(std::move(delayedTouch));
1446 qCDebug(lcTouchCmprs) <<
"delivering" << e.get();
1447 compressedTouchCount = 0;
1448 deliverPointerEvent(e.get());
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
1463 Q_Q(QQuickDeliveryAgent);
1464 qCDebug(lcFocus) <<
"deactivated" << win->title();
1465 const auto inputDevices = QInputDevice::devices();
1466 for (
auto device : inputDevices) {
1467 if (
auto pointingDevice = qobject_cast<
const QPointingDevice *>(device)) {
1468 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(pointingDevice));
1469 for (
auto epd : devPriv->activePoints.values()) {
1470 if (!epd.exclusiveGrabber.isNull()) {
1471 bool relevant =
false;
1472 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(epd.exclusiveGrabber.data()))
1473 relevant = (item->window() == win);
1474 else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(epd.exclusiveGrabber.data())) {
1475 if (handler->parentItem())
1476 relevant = (handler->parentItem()->window() == win && epd.exclusiveGrabberContext.data() == q);
1483 devPriv->setExclusiveGrabber(
nullptr, epd.eventPoint,
nullptr);
1492void QQuickDeliveryAgentPrivate::handleWindowHidden(QQuickWindow *win)
1494 qCDebug(lcFocus) <<
"hidden" << win->title();
1496 lastMousePosition = QPointF();
1499bool QQuickDeliveryAgentPrivate::allUpdatedPointsAccepted(
const QPointerEvent *ev)
1501 for (
auto &point : ev->points()) {
1502 if (point.state() != QEventPoint::State::Pressed && !point.isAccepted())
1509
1510
1511
1512
1513
1514void QQuickDeliveryAgentPrivate::localizePointerEvent(QPointerEvent *ev,
const QQuickItem *dest)
1516 for (
int i = 0; i < ev->pointCount(); ++i) {
1517 auto &point = ev->point(i);
1518 QMutableEventPoint::setPosition(point, dest->mapFromScene(point.scenePosition()));
1519 qCDebug(lcPtrLoc) << ev->type() <<
"@" << point.scenePosition() <<
"to"
1520 << dest <<
"@" << dest->mapToScene(QPointF()) <<
"->" << point;
1524QList<QObject *> QQuickDeliveryAgentPrivate::exclusiveGrabbers(QPointerEvent *ev)
1526 QList<QObject *> result;
1527 for (
const QEventPoint &point : ev->points()) {
1528 if (QObject *grabber = ev->exclusiveGrabber(point)) {
1529 if (!result.contains(grabber))
1536bool QQuickDeliveryAgentPrivate::anyPointGrabbed(
const QPointerEvent *ev)
1538 for (
const QEventPoint &point : ev->points()) {
1539 if (ev->exclusiveGrabber(point) || !ev->passiveGrabbers(point).isEmpty())
1545bool QQuickDeliveryAgentPrivate::allPointsGrabbed(
const QPointerEvent *ev)
1547 for (
const auto &point : ev->points()) {
1548 if (!ev->exclusiveGrabber(point) && ev->passiveGrabbers(point).isEmpty())
1554bool QQuickDeliveryAgentPrivate::isMouseEvent(
const QPointerEvent *ev)
1556 switch (ev->type()) {
1557 case QEvent::MouseButtonPress:
1558 case QEvent::MouseButtonRelease:
1559 case QEvent::MouseButtonDblClick:
1560 case QEvent::MouseMove:
1567bool QQuickDeliveryAgentPrivate::isMouseOrWheelEvent(
const QPointerEvent *ev)
1569 return isMouseEvent(ev) || ev->type() == QEvent::Wheel;
1572bool QQuickDeliveryAgentPrivate::isHoverEvent(
const QPointerEvent *ev)
1574 switch (ev->type()) {
1575 case QEvent::HoverEnter:
1576 case QEvent::HoverMove:
1577 case QEvent::HoverLeave:
1584bool QQuickDeliveryAgentPrivate::isTouchEvent(
const QPointerEvent *ev)
1586 switch (ev->type()) {
1587 case QEvent::TouchBegin:
1588 case QEvent::TouchUpdate:
1589 case QEvent::TouchEnd:
1590 case QEvent::TouchCancel:
1597bool QQuickDeliveryAgentPrivate::isTabletEvent(
const QPointerEvent *ev)
1599#if QT_CONFIG(tabletevent)
1600 switch (ev->type()) {
1601 case QEvent::TabletPress:
1602 case QEvent::TabletMove:
1603 case QEvent::TabletRelease:
1604 case QEvent::TabletEnterProximity:
1605 case QEvent::TabletLeaveProximity:
1616bool QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(
const QPointerEvent *ev)
1618 const auto devType = ev->device()->type();
1619 return devType == QInputDevice::DeviceType::Mouse ||
1620 devType == QInputDevice::DeviceType::TouchPad;
1623bool QQuickDeliveryAgentPrivate::isSynthMouse(
const QPointerEvent *ev)
1625 return (!isEventFromMouseOrTouchpad(ev) && isMouseEvent(ev));
1629
1630
1631
1632bool QQuickDeliveryAgentPrivate::isSinglePointDevice(
const QInputDevice *dev)
1634 switch (dev->type()) {
1635 case QInputDevice::DeviceType::Mouse:
1636 case QInputDevice::DeviceType::TouchPad:
1637 case QInputDevice::DeviceType::Puck:
1638 case QInputDevice::DeviceType::Stylus:
1639 case QInputDevice::DeviceType::Airbrush:
1641 case QInputDevice::DeviceType::TouchScreen:
1642 case QInputDevice::DeviceType::Keyboard:
1643 case QInputDevice::DeviceType::Unknown:
1644 case QInputDevice::DeviceType::AllDevices:
1650QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(
const QInputDevice *device)
1652 QInputDevicePrivate *devPriv = QInputDevicePrivate::get(
const_cast<QInputDevice *>(device));
1653 if (devPriv->qqExtra)
1654 return static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1655 auto extra =
new QQuickPointingDeviceExtra;
1656 devPriv->qqExtra = extra;
1657 QObject::connect(device, &QObject::destroyed, device, [devPriv]() {
1658 delete static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1659 devPriv->qqExtra =
nullptr;
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
1692 if (isSubsceneAgent)
1695 QEventPoint::States states = event->touchPointStates();
1696 if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
1697 qCDebug(lcTouchCmprs) <<
"no compression" << event;
1702 if (!delayedTouch) {
1703 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points()));
1704 delayedTouch->setTimestamp(event->timestamp());
1705 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1706 auto &tp = delayedTouch->point(i);
1707 QMutableEventPoint::detach(tp);
1709 ++compressedTouchCount;
1710 qCDebug(lcTouchCmprs) <<
"delayed" << compressedTouchCount << delayedTouch.get();
1711 if (QQuickWindow *window = rootItem->window())
1712 window->maybeUpdate();
1717 if (delayedTouch->type() == event->type() &&
1718 delayedTouch->device() == event->device() &&
1719 delayedTouch->modifiers() == event->modifiers() &&
1720 delayedTouch->pointCount() == event->pointCount())
1723 bool mismatch =
false;
1725 auto tpts = event->points();
1726 for (qsizetype i = 0; i < event->pointCount(); ++i) {
1727 const auto &tp = tpts.at(i);
1728 const auto &tpDelayed = delayedTouch->point(i);
1729 if (tp.id() != tpDelayed.id()) {
1734 if (tpDelayed.state() == QEventPoint::State::Updated && tp.state() == QEventPoint::State::Stationary)
1735 QMutableEventPoint::setState(tpts[i], QEventPoint::State::Updated);
1742 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts));
1743 delayedTouch->setTimestamp(event->timestamp());
1744 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1745 auto &tp = delayedTouch->point(i);
1746 QMutableEventPoint::detach(tp);
1748 ++compressedTouchCount;
1749 qCDebug(lcTouchCmprs) <<
"coalesced" << compressedTouchCount << delayedTouch.get();
1750 if (QQuickWindow *window = rootItem->window())
1751 window->maybeUpdate();
1757 deliverDelayedTouchEvent();
1758 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(),
1759 event->modifiers(), event->points()));
1760 delayedTouch->setTimestamp(event->timestamp());
1768void QQuickDeliveryAgentPrivate::handleTouchEvent(QTouchEvent *event)
1770 Q_Q(QQuickDeliveryAgent);
1771 translateTouchEvent(event);
1773 if (event->pointCount()) {
1774 auto &point = event->point(0);
1775 if (point.state() == QEventPoint::State::Released) {
1776 lastMousePosition = QPointF();
1778 lastMousePosition = point.position();
1782 qCDebug(lcTouch) << q << event;
1784 static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet(
"QML_NO_TOUCH_COMPRESSION");
1786 if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) {
1787 deliverPointerEvent(event);
1791 if (!compressTouchEvent(event)) {
1793 deliverDelayedTouchEvent();
1794 qCDebug(lcTouchCmprs) <<
"resuming delivery" << event;
1796 deliverPointerEvent(event);
1801
1802
1803void QQuickDeliveryAgentPrivate::handleMouseEvent(QMouseEvent *event)
1805 Q_Q(QQuickDeliveryAgent);
1809 if (event->source() == Qt::MouseEventSynthesizedBySystem &&
1810 !(event->button() == Qt::RightButton && allowSyntheticRightClick())) {
1814 qCDebug(lcMouse) << q << event;
1816 switch (event->type()) {
1817 case QEvent::MouseButtonPress:
1818 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
1820 deliverPointerEvent(event);
1822 case QEvent::MouseButtonRelease:
1823 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
1825 deliverPointerEvent(event);
1826#if QT_CONFIG(cursor)
1827 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1830 case QEvent::MouseButtonDblClick:
1831 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1832 event->button(), event->buttons());
1833 deliverPointerEvent(event);
1835 case QEvent::MouseMove: {
1836 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
1837 event->position().x(), event->position().y());
1839 const QPointF last = lastMousePosition.isNull() ? event->scenePosition() : lastMousePosition;
1840 lastMousePosition = event->scenePosition();
1841 qCDebug(lcHoverTrace) << q << event <<
"mouse pos" << last <<
"->" << lastMousePosition;
1842 if (!event->points().size() || !event->exclusiveGrabber(event->point(0))) {
1843 bool accepted = deliverHoverEvent(event->scenePosition(), last, event->modifiers(), event->timestamp());
1844 event->setAccepted(accepted);
1846 deliverPointerEvent(event);
1847#if QT_CONFIG(cursor)
1849 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874void QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents(QQuickWindow *win)
1876 Q_Q(QQuickDeliveryAgent);
1877 QQuickDeliveryAgent *deliveringAgent = QQuickDeliveryAgentPrivate::currentEventDeliveryAgent;
1878 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = q;
1881 deliverDelayedTouchEvent();
1885 QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
1886 if (ut && ut->hasStartAnimationPending())
1887 ut->startAnimations();
1892#if !defined(Q_OS_WEBOS)
1902 if (frameSynchronousHoverInterval >= 0) {
1903 const bool timerActive = frameSynchronousHoverInterval > 0;
1904 const bool timerMature = frameSynchronousHoverTimer.elapsed() >= frameSynchronousHoverInterval;
1905 if (timerActive && !timerMature) {
1906 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery delayed: elapsed"
1907 << frameSynchronousHoverTimer.elapsed() <<
"<" << frameSynchronousHoverInterval;
1908 if (!frameSynchronousDelayTimer.isActive())
1909 frameSynchronousDelayTimer.start(frameSynchronousHoverInterval - frameSynchronousHoverTimer.elapsed(), q);
1910 }
else if (!win->mouseGrabberItem() && !lastMousePosition.isNull() &&
1911 (timerMature || QQuickWindowPrivate::get(win)->dirtyItemList)) {
1912 frameSynchronousDelayTimer.stop();
1913 qCDebug(lcHoverTrace) << q <<
"delivering frame-sync hover to root @" << lastMousePosition
1914 <<
"after elapsed time" << frameSynchronousHoverTimer.elapsed();
1915 if (deliverHoverEvent(lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0)) {
1916#if QT_CONFIG(cursor)
1917 QQuickWindowPrivate::get(rootItem->window())->updateCursor(
1918 sceneTransform ? sceneTransform->map(lastMousePosition) : lastMousePosition, rootItem);
1923 frameSynchronousHoverTimer.restart();
1924 ++frameSynchronousHover_counter;
1925 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery done: round" << frameSynchronousHover_counter;
1931 if (Q_UNLIKELY(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent &&
1932 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent != q))
1933 qCWarning(lcPtr,
"detected interleaved frame-sync and actual events");
1934 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveringAgent;
1938
1939
1940
1941
1942
1943
1944
1945void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition,
1946 const QPointerEvent *event,
const QEventPoint &point)
1948 Q_Q(QQuickDeliveryAgent);
1949 const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
1950 transition == QPointingDevice::GrabTransition::GrabPassive);
1953 if (
auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
1954 if (handler->parentItem()) {
1955 auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
1956 if (itemPriv->deliveryAgent() == q) {
1958 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1959 const_cast<QEventPoint &>(point));
1964 QEventPoint lostPoint(point);
1965 QMutableEventPoint::setPosition(lostPoint, handler->parentItem()->mapFromScene(point.scenePosition()));
1966 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1968 qCDebug(lcPtrLoc) << event->type() <<
"@" << point.scenePosition()
1969 <<
"to old handler" << grabber <<
"->" << lostPoint;
1975 if (isSubsceneAgent && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
1976 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
1978 }
else if (!isSubsceneAgent) {
1979 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1980 const_cast<QEventPoint &>(point));
1982 }
else if (
auto *grabberItem = qmlobject_cast<QQuickItem *>(grabber)) {
1983 switch (transition) {
1984 case QPointingDevice::CancelGrabExclusive:
1985 case QPointingDevice::UngrabExclusive:
1986 if (isDeliveringTouchAsMouse() || isSinglePointDevice(point.device())) {
1989 QMutableSinglePointEvent e(QEvent::UngrabMouse, point.device(), point);
1990 hasFiltered.clear();
1991 if (!sendFilteredMouseEvent(&e, grabberItem, grabberItem->parentItem())) {
1992 lastUngrabbed = grabberItem;
1993 grabberItem->mouseUngrabEvent();
1998 bool allReleasedOrCancelled =
true;
1999 if (transition == QPointingDevice::UngrabExclusive && event) {
2000 for (
const auto &pt : event->points()) {
2001 if (pt.state() != QEventPoint::State::Released) {
2002 allReleasedOrCancelled =
false;
2007 if (allReleasedOrCancelled)
2008 grabberItem->touchUngrabEvent();
2014 auto *itemPriv = QQuickItemPrivate::get(grabberItem);
2017 if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
2018 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
2021 if (currentEventDeliveryAgent == q && event && event->device()) {
2022 switch (transition) {
2023 case QPointingDevice::GrabPassive: {
2024 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2026 QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q);
2027 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2029 case QPointingDevice::GrabExclusive: {
2030 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2032 epd->exclusiveGrabberContext = q;
2033 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2035 case QPointingDevice::CancelGrabExclusive:
2036 case QPointingDevice::UngrabExclusive:
2039 case QPointingDevice::UngrabPassive:
2040 case QPointingDevice::CancelGrabPassive:
2043 case QPointingDevice::OverrideGrabPassive:
2051
2052
2053
2054
2055
2056
2057
2058
2059void QQuickDeliveryAgentPrivate::ensureDeviceConnected(
const QPointingDevice *dev)
2061 Q_Q(QQuickDeliveryAgent);
2062 if (knownPointingDevices.contains(dev))
2064 knownPointingDevices.append(dev);
2065 connect(dev, &QPointingDevice::grabChanged,
this, &QQuickDeliveryAgentPrivate::onGrabChanged);
2066 QObject::connect(dev, &QObject::destroyed, q, [
this, dev] {
this->knownPointingDevices.removeAll(dev);});
2070
2071
2072
2073
2074
2075
2076void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
2078 Q_Q(QQuickDeliveryAgent);
2079 if (isTabletEvent(event))
2080 qCDebug(lcTablet) << q << event;
2085 ++pointerEventRecursionGuard;
2086 eventsInDelivery.push(event);
2092 QVarLengthArray<QPointF, 16> originalScenePositions;
2093 if (sceneTransform) {
2094 originalScenePositions.resize(event->pointCount());
2095 for (
int i = 0; i < event->pointCount(); ++i) {
2096 auto &pt = event->point(i);
2097 originalScenePositions[i] = pt.scenePosition();
2098 QMutableEventPoint::setScenePosition(pt, sceneTransform->map(pt.scenePosition()));
2099 qCDebug(lcPtrLoc) << q << event->type() << pt.id() <<
"transformed scene pos" << pt.scenePosition();
2101 }
else if (isSubsceneAgent) {
2102 qCDebug(lcPtrLoc) << q << event->type() <<
"no scene transform set";
2105 skipDelivery.clear();
2106 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
2108 qCDebug(lcPtr) << q <<
"delivering with" << sceneTransform << event;
2110 qCDebug(lcPtr) << q <<
"delivering" << event;
2111 for (
int i = 0; i < event->pointCount(); ++i)
2112 event->point(i).setAccepted(
false);
2114 if (event->isBeginEvent()) {
2115 ensureDeviceConnected(event->pointingDevice());
2116 if (event->type() == QEvent::MouseButtonPress && rootItem->window()
2117 &&
static_cast<QSinglePointEvent *>(event)->button() == Qt::RightButton) {
2118 QQuickWindowPrivate::get(rootItem->window())->rmbContextMenuEventEnabled =
true;
2120 if (!deliverPressOrReleaseEvent(event))
2121 event->setAccepted(
false);
2124 auto isHoveringMoveEvent = [](QPointerEvent *event) ->
bool {
2125 if (event->type() == QEvent::MouseMove) {
2126 const auto *spe =
static_cast<
const QSinglePointEvent *>(event);
2127 if (spe->button() == Qt::NoButton && spe->buttons() == Qt::NoButton)
2134
2135
2136
2137
2138
2139
2140
2141
2142 if (!allUpdatedPointsAccepted(event) && !isHoveringMoveEvent(event))
2143 deliverUpdatedPoints(event);
2144 if (event->isEndEvent())
2145 deliverPressOrReleaseEvent(event,
true);
2149 if (isTouchEvent(event) && touchMouseId >= 0) {
2150 if (
static_cast<QTouchEvent *>(event)->touchPointStates() == QEventPoint::State::Released) {
2151 cancelTouchMouseSynthesis();
2153 auto touchMousePoint = event->pointById(touchMouseId);
2154 if (touchMousePoint && touchMousePoint->state() == QEventPoint::State::Released)
2155 cancelTouchMouseSynthesis();
2159 eventsInDelivery.pop();
2160 if (sceneTransform) {
2161 for (
int i = 0; i < event->pointCount(); ++i)
2162 QMutableEventPoint::setScenePosition(event->point(i), originalScenePositions.at(i));
2164 --pointerEventRecursionGuard;
2165 lastUngrabbed =
nullptr;
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205QList<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
const QEvent *event,
int pointId,
2206 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate)
const
2208 QList<QQuickItem *> targets;
2209 eventTargetsAppend(item, event, pointId, localPos, scenePos, predicate, targets);
2214
2215
2216
2217
2218
2220void QQuickDeliveryAgentPrivate::eventTargetsAppend(QQuickItem *item,
const QEvent *event,
int pointId,
2221 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate,
2222 QList<QQuickItem *> &targets)
const
2224 auto itemPrivate = QQuickItemPrivate::get(item);
2229 if (item != rootItem && !itemPrivate->eventHandlingBounds().contains(localPos) &&
2230 itemPrivate->effectivelyClipsEventHandlingChildren()) {
2231 qCDebug(lcPtrLoc) <<
"skipping because" << localPos <<
"is outside rectangular bounds of" << item;
2237 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2242 Q_ASSERT(event->isPointerEvent());
2243 QPointerEvent *pev =
const_cast<QPointerEvent *>(
static_cast<
const QPointerEvent *>(event));
2244 QEventPoint *point = pev->pointById(pointId);
2246 QMutableEventPoint::setPosition(*point, localPos);
2248 const std::optional<
bool> override = predicate(item, event);
2249 const bool relevant = override.has_value() ? override.value()
2250 : item == rootItem || item->contains(localPos);
2255 bool selfEmitted = !relevant;
2256 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2257 QQuickItem *child = children.at(ii);
2258 if (!selfEmitted && child->z() < 0) {
2259 targets.append(item);
2263 auto childPrivate = QQuickItemPrivate::get(child);
2264 if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
2265 (childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
2268 QTransform childToParent;
2269 childPrivate->itemToParentTransform(&childToParent);
2270 const QPointF childLocalPos = childToParent.inverted().map(localPos);
2271 eventTargetsAppend(child, event, pointId, childLocalPos, scenePos, predicate, targets);
2276 targets.append(item);
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308QList<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *item,
const QPointerEvent *event,
const QEventPoint &point,
2309 bool checkMouseButtons,
bool checkAcceptsTouch)
const
2311 auto predicate = [point, checkMouseButtons, checkAcceptsTouch](QQuickItem *item,
const QEvent *ev) -> std::optional<
bool> {
2312 const QPointerEvent *event =
static_cast<
const QPointerEvent *>(ev);
2313 auto itemPrivate = QQuickItemPrivate::get(item);
2314 if (itemPrivate->hasPointerHandlers()) {
2315 if (itemPrivate->anyPointerHandlerWants(event, point))
2318 if (checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
2320 if (checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
2324 return std::nullopt;
2327 return eventTargets(item, event, point.id(), item->mapFromScene(point.scenePosition()), point.scenePosition(), predicate);
2331
2332
2333
2334QList<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(
const QList<QQuickItem *> &list1,
const QList<QQuickItem *> &list2)
const
2336 QList<QQuickItem *> targets = list1;
2340 int insertPosition = targets.size();
2341 for (
int i = list2.size() - 1; i >= 0; --i) {
2342 int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
2343 if (newInsertPosition >= 0) {
2344 Q_ASSERT(newInsertPosition <= insertPosition);
2345 insertPosition = newInsertPosition;
2348 if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
2349 targets.insert(insertPosition, list2.at(i));
2355
2356
2357void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
2359 Q_Q(
const QQuickDeliveryAgent);
2361 const auto grabbers = exclusiveGrabbers(event);
2362 hasFiltered.clear();
2363 for (
auto grabber : grabbers) {
2365 QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
2368 QQuickPointerHandler *handler =
static_cast<QQuickPointerHandler *>(grabber);
2369 receiver =
static_cast<QQuickPointerHandler *>(grabber)->parentItem();
2373 hasFiltered.clear();
2374 if (sendFilteredPointerEvent(event, receiver))
2376 localizePointerEvent(event, receiver);
2378 handler->handlePointerEvent(event);
2384 hasFiltered.clear();
2386 deliverMatchingPointsToItem(receiver,
true, event);
2390 for (
auto &point : event->points()) {
2391 auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
2392 if (Q_UNLIKELY(!epd)) {
2393 qWarning() <<
"point is not in activePoints" << point;
2396 QList<QPointer<QObject>> relevantPassiveGrabbers;
2397 for (
int i = 0; i < epd->passiveGrabbersContext.size(); ++i) {
2398 if (epd->passiveGrabbersContext.at(i).data() == q)
2399 relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
2401 if (!relevantPassiveGrabbers.isEmpty())
2402 deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
2405 if (event->type() == QEvent::TouchUpdate) {
2406 for (
const auto &[item, id] : hoverItems) {
2408 bool res = deliverHoverEventToItem(item, item->mapFromScene(point.scenePosition()), point.scenePosition(), point.sceneLastPosition(),
2409 point.globalPosition(), event->modifiers(), event->timestamp(), HoverChange::Set);
2411 Q_ASSERT(([
this, item = item.get(), res]{
2412 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
2413 return !res || it2->hoverId != 0;
2424 if (!allPointsGrabbed(event)) {
2425 QList<QQuickItem *> targetItems;
2426 for (
auto &point : event->points()) {
2429 if (point.state() == QEventPoint::Pressed || qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(point)))
2431 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point,
false,
false);
2432 if (targetItems.size()) {
2433 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2435 targetItems = targetItemsForPoint;
2438 for (QQuickItem *item : targetItems) {
2439 if (grabbers.contains(item))
2441 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2442 localizePointerEvent(event, item);
2443 itemPrivate->handlePointerEvent(event,
true);
2444 if (allPointsGrabbed(event))
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event,
bool handlersOnly)
2491 QList<QQuickItem *> targetItems;
2492 const bool isTouch = isTouchEvent(event);
2493 if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) {
2494 if (
auto point =
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) {
2504 if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint)))
2505 cancelTouchMouseSynthesis();
2507 qCWarning(lcTouchTarget) <<
"during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId <<
"is missing from" << event;
2510 for (
int i = 0; i < event->pointCount(); ++i) {
2511 auto &point = event->point(i);
2515 if (isTouch && point.state() == QEventPoint::Pressed)
2516 resetIfDoubleTapPrevented(point);
2517 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch);
2518 if (targetItems.size()) {
2519 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2521 targetItems = targetItemsForPoint;
2525 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
2527 for (
auto &item : safeTargetItems) {
2531 if (isSubsceneAgent)
2532 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
2534 hasFiltered.clear();
2535 if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
2536 if (event->isAccepted())
2538 skipDelivery.append(item);
2543 if (skipDelivery.contains(item))
2548 for (
int i = 0; i < event->pointCount(); ++i)
2549 event->point(i).setAccepted(
false);
2551 deliverMatchingPointsToItem(item,
false, event, handlersOnly);
2552 if (event->allPointsAccepted())
2553 handlersOnly =
true;
2559 return handlersOnly;
2563
2564
2565
2566
2567
2568
2569
2570void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item,
bool isGrabber, QPointerEvent *pointerEvent,
bool handlersOnly)
2572 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2573#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
2578 if (itemPrivate->wasDeleted)
2581 localizePointerEvent(pointerEvent, item);
2582 bool isMouse = isMouseEvent(pointerEvent);
2586 if (pointerEvent->type() != QEvent::MouseButtonDblClick)
2587 itemPrivate->handlePointerEvent(pointerEvent);
2594 if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent()
2595 && !exclusiveGrabbers(pointerEvent).contains(item))
2599 if (sendFilteredPointerEvent(pointerEvent, item))
2605 auto button =
static_cast<QSinglePointEvent *>(pointerEvent)->button();
2606 if ((isGrabber && button == Qt::NoButton) || item->acceptedMouseButtons().testFlag(button)) {
2609 auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0));
2610 pointerEvent->accept();
2611 if (isGrabber && sendFilteredPointerEvent(pointerEvent, item))
2613 localizePointerEvent(pointerEvent, item);
2614 QCoreApplication::sendEvent(item, pointerEvent);
2615 if (pointerEvent->isAccepted()) {
2616 auto &point = pointerEvent->point(0);
2617 auto mouseGrabber = pointerEvent->exclusiveGrabber(point);
2618 if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
2624 if (item != lastUngrabbed) {
2625 item->mouseUngrabEvent();
2626 lastUngrabbed = item;
2628 }
else if (item->isEnabled() && item->isVisible() && point.state() == QEventPoint::State::Pressed) {
2629 pointerEvent->setExclusiveGrabber(point, item);
2631 point.setAccepted(
true);
2637 if (!isTouchEvent(pointerEvent))
2640 bool eventAccepted =
false;
2641 QMutableTouchEvent touchEvent;
2642 itemPrivate->localizedTouchEvent(
static_cast<QTouchEvent *>(pointerEvent),
false, &touchEvent);
2643 if (touchEvent.type() == QEvent::None)
2646 if (item->acceptTouchEvents()) {
2647 qCDebug(lcTouch) <<
"considering delivering" << &touchEvent <<
" to " << item;
2650 qCDebug(lcTouch) <<
"actually delivering" << &touchEvent <<
" to " << item;
2651 QCoreApplication::sendEvent(item, &touchEvent);
2652 eventAccepted = touchEvent.isAccepted();
2655 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2656 !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
2657 deliverTouchAsMouse(item, &touchEvent);
2661 Q_ASSERT(item->acceptTouchEvents());
2662 if (eventAccepted) {
2663 bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
2664 for (
int i = 0; i < touchEvent.pointCount(); ++i) {
2665 auto &point = touchEvent.point(i);
2667 point.setAccepted();
2669 if (isPressOrRelease && !(itemPrivate->deliveryAgent() && pointerEvent->exclusiveGrabber(point)))
2670 pointerEvent->setExclusiveGrabber(point, item);
2675 for (
const auto &point: touchEvent.points()) {
2676 if (point.state() == QEventPoint::State::Pressed) {
2677 if (pointerEvent->exclusiveGrabber(point) == item) {
2678 qCDebug(lcTouchTarget) <<
"TP" << Qt::hex << point.id() <<
"disassociated";
2679 pointerEvent->setExclusiveGrabber(point,
nullptr);
2686#if QT_CONFIG(quick_draganddrop)
2687void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
2689 QObject *formerTarget = grabber->target();
2690 grabber->resetTarget();
2691 QQuickDragGrabber::iterator grabItem = grabber->begin();
2692 if (grabItem != grabber->end()) {
2693 Q_ASSERT(event->type() != QEvent::DragEnter);
2694 if (event->type() == QEvent::Drop) {
2695 QDropEvent *e =
static_cast<QDropEvent *>(event);
2696 for (e->setAccepted(
false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
2697 QPointF p = (**grabItem)->mapFromScene(e->position().toPoint());
2698 QDropEvent translatedEvent(
2700 e->possibleActions(),
2704 QQuickDropEventEx::copyActions(&translatedEvent, *e);
2705 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2706 e->setAccepted(translatedEvent.isAccepted());
2707 e->setDropAction(translatedEvent.dropAction());
2708 grabber->setTarget(**grabItem);
2711 if (event->type() != QEvent::DragMove) {
2712 QDragLeaveEvent leaveEvent;
2713 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2714 QCoreApplication::sendEvent(**grabItem, &leaveEvent);
2715 grabber->ignoreList().clear();
2718 QDragMoveEvent *moveEvent =
static_cast<QDragMoveEvent *>(event);
2722 QVarLengthArray<QQuickItem*, 64> currentGrabItems;
2723 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2724 currentGrabItems.append(**grabItem);
2727 QDragEnterEvent enterEvent(
2728 moveEvent->position(),
2729 moveEvent->possibleActions(),
2730 moveEvent->mimeData(),
2731 moveEvent->buttons(),
2732 moveEvent->modifiers());
2733 QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
2734 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, ¤tGrabItems,
2737 for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
2738 int i = currentGrabItems.indexOf(**grabItem);
2740 currentGrabItems.remove(i);
2742 QDragMoveEvent translatedEvent(
2743 (**grabItem)->mapFromScene(moveEvent->position()),
2744 moveEvent->possibleActions(),
2745 moveEvent->mimeData(),
2746 moveEvent->buttons(),
2747 moveEvent->modifiers());
2748 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
2749 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2750 event->setAccepted(translatedEvent.isAccepted());
2751 QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
2756 QDragLeaveEvent leaveEvent;
2757 for (QQuickItem *i : currentGrabItems)
2758 QCoreApplication::sendEvent(i, &leaveEvent);
2763 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
2764 QDragMoveEvent *e =
static_cast<QDragMoveEvent *>(event);
2765 QDragEnterEvent enterEvent(
2767 e->possibleActions(),
2771 QQuickDropEventEx::copyActions(&enterEvent, *e);
2772 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
2774 grabber->ignoreList().clear();
2778bool QQuickDeliveryAgentPrivate::deliverDragEvent(
2779 QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
2780 QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
2782 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2783 if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
2785 QPointF p = item->mapFromScene(event->position().toPoint());
2786 bool itemContained = item->contains(p);
2788 const int itemIndex = grabber->ignoreList().indexOf(item);
2789 if (!itemContained) {
2791 grabber->ignoreList().remove(itemIndex);
2793 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
2797 QDragEnterEvent enterEvent(
2799 event->possibleActions(),
2802 event->modifiers());
2803 QQuickDropEventEx::copyActions(&enterEvent, *event);
2804 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2807 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2808 if (children.at(ii)->z() < 0)
2810 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2814 if (itemContained) {
2817 if (currentGrabItems && currentGrabItems->contains(item)) {
2818 grabber->grab(item);
2819 grabber->setTarget(item);
2823 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
2824 if (event->type() == QEvent::DragEnter) {
2826 QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
2827 if (formerTargetItem && currentGrabItems) {
2828 QDragLeaveEvent leaveEvent;
2829 QCoreApplication::sendEvent(formerTarget, &leaveEvent);
2833 currentGrabItems->removeAll(formerTarget);
2835 }
else if (itemIndex >= 0) {
2840 QDragMoveEvent translatedEvent(p, event->possibleActions(), event->mimeData(),
2841 event->buttons(), event->modifiers(), event->type());
2842 QQuickDropEventEx::copyActions(&translatedEvent, *event);
2843 translatedEvent.setAccepted(event->isAccepted());
2844 QCoreApplication::sendEvent(item, &translatedEvent);
2845 event->setAccepted(translatedEvent.isAccepted());
2846 event->setDropAction(translatedEvent.dropAction());
2847 if (event->type() == QEvent::DragEnter) {
2848 if (translatedEvent.isAccepted()) {
2849 grabber->grab(item);
2850 grabber->setTarget(item);
2852 }
else if (itemIndex < 0) {
2853 grabber->ignoreList().append(item);
2862 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2863 if (children.at(ii)->z() >= 0)
2865 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2874
2875
2876
2877
2878
2879
2880
2881bool QQuickDeliveryAgentPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2883 return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
2887
2888
2889bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2891 if (!allowChildEventFiltering)
2893 if (!filteringParent)
2895 bool filtered =
false;
2896 const bool hasHandlers = QQuickItemPrivate::get(receiver)->hasPointerHandlers();
2897 if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
2898 hasFiltered.append(filteringParent);
2899 if (isMouseEvent(event)) {
2900 if (receiver->acceptedMouseButtons()) {
2901 const bool wasAccepted = event->allPointsAccepted();
2902 Q_ASSERT(event->pointCount());
2903 localizePointerEvent(event, receiver);
2904 event->setAccepted(
true);
2905 auto oldMouseGrabber = event->exclusiveGrabber(event->point(0));
2906 if (filteringParent->childMouseEventFilter(receiver, event)) {
2907 qCDebug(lcMouse) <<
"mouse event intercepted by childMouseEventFilter of " << filteringParent;
2908 skipDelivery.append(filteringParent);
2910 if (event->isAccepted() && event->isBeginEvent()) {
2911 auto &point = event->point(0);
2912 auto mouseGrabber = event->exclusiveGrabber(point);
2913 if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
2914 receiver->mouseUngrabEvent();
2916 event->setExclusiveGrabber(point, receiver);
2921 event->setAccepted(wasAccepted);
2924 }
else if (isTouchEvent(event)) {
2925 const bool acceptsTouchEvents = receiver->acceptTouchEvents() || hasHandlers;
2926 auto device = event->device();
2927 if (device->type() == QInputDevice::DeviceType::TouchPad &&
2928 device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
2929 qCDebug(lcTouchTarget) <<
"skipping filtering of synth-mouse event from" << device;
2930 }
else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
2933 QMutableTouchEvent filteringParentTouchEvent;
2934 QQuickItemPrivate::get(receiver)->localizedTouchEvent(
static_cast<QTouchEvent *>(event),
true, &filteringParentTouchEvent);
2935 if (filteringParentTouchEvent.type() != QEvent::None) {
2936 qCDebug(lcTouch) <<
"letting parent" << filteringParent <<
"filter for" << receiver << &filteringParentTouchEvent;
2937 filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent);
2939 qCDebug(lcTouch) <<
"touch event intercepted by childMouseEventFilter of " << filteringParent;
2940 event->setAccepted(filteringParentTouchEvent.isAccepted());
2941 skipDelivery.append(filteringParent);
2942 if (event->isAccepted()) {
2943 for (
auto point : filteringParentTouchEvent.points()) {
2944 const QQuickItem *exclusiveGrabber = qobject_cast<
const QQuickItem *>(event->exclusiveGrabber(point));
2954 const bool grabberInsideFilteringParent = exclusiveGrabber &&
2955 exclusiveGrabber->acceptTouchEvents() &&
2956 filteringParent->isAncestorOf(
const_cast<QQuickItem *>(exclusiveGrabber));
2957 if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab() || grabberInsideFilteringParent)
2958 event->setExclusiveGrabber(point, filteringParent);
2966 for (
int i = 0; i < event->pointCount(); ++i)
2967 event->point(i).setAccepted(
false);
2969 }
else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2970 !filteringParent->acceptTouchEvents()) {
2971 qCDebug(lcTouch) <<
"touch event NOT intercepted by childMouseEventFilter of " << filteringParent
2972 <<
"; accepts touch?" << filteringParent->acceptTouchEvents()
2973 <<
"receiver accepts touch?" << acceptsTouchEvents
2974 <<
"so, letting parent filter a synth-mouse event";
2976 for (
auto &tp : filteringParentTouchEvent.points()) {
2978 switch (tp.state()) {
2979 case QEventPoint::State::Pressed:
2980 t = QEvent::MouseButtonPress;
2982 case QEventPoint::State::Released:
2983 t = QEvent::MouseButtonRelease;
2985 case QEventPoint::State::Stationary:
2988 t = QEvent::MouseMove;
2992 bool touchMouseUnset = (touchMouseId == -1);
2994 if (touchMouseUnset || touchMouseId == tp.id()) {
2997 QMutableSinglePointEvent mouseEvent;
2998 touchToMouseEvent(t, tp, &filteringParentTouchEvent, &mouseEvent);
3002 touchMouseId = tp.id();
3003 touchMouseDevice = event->pointingDevice();
3004 filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent);
3006 qCDebug(lcTouch) <<
"touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
3007 event->setAccepted(mouseEvent.isAccepted());
3008 skipDelivery.append(filteringParent);
3009 if (event->isAccepted() && event->isBeginEvent()) {
3010 qCDebug(lcTouchTarget) <<
"TP (mouse)" << Qt::hex << tp.id() <<
"->" << filteringParent;
3011 filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent);
3012 touchMouseUnset =
false;
3013 filteringParent->grabMouse();
3016 if (touchMouseUnset)
3019 cancelTouchMouseSynthesis();
3020 mouseEvent.point(0).setAccepted(
false);
3031 return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045bool QQuickDeliveryAgentPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3047 if (!filteringParent)
3050 QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
3051 if (filteringParentPrivate->replayingPressEvent)
3054 bool filtered =
false;
3055 if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
3056 hasFiltered.append(filteringParent);
3057 if (filteringParent->childMouseEventFilter(receiver, event)) {
3059 skipDelivery.append(filteringParent);
3061 qCDebug(lcMouseTarget) <<
"for" << receiver << filteringParent <<
"childMouseEventFilter ->" << filtered;
3064 return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
3068
3069
3070
3071
3072
3073
3074bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event,
int startDragThreshold)
3076 QStyleHints *styleHints = QGuiApplication::styleHints();
3077 bool dragVelocityLimitAvailable = event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
3078 && styleHints->startDragVelocity();
3079 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3080 if (dragVelocityLimitAvailable) {
3081 QVector2D velocityVec = event->point(0).velocity();
3082 qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
3083 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3085 return overThreshold;
3089
3090
3091
3092
3093
3094
3095bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const QEventPoint &tp,
int startDragThreshold)
3097 QStyleHints *styleHints = qApp->styleHints();
3098 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3099 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
3100 if (!overThreshold && dragVelocityLimitAvailable) {
3101 qreal velocity = axis == Qt::XAxis ? tp.velocity().x() : tp.velocity().y();
3102 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3104 return overThreshold;
3108
3109
3110
3111
3112bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
3114 int threshold = qApp->styleHints()->startDragDistance();
3115 return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
3119
3120
3121
3122
3123
3124
3125QList<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item,
const QContextMenuEvent *event)
const
3127 auto predicate = [](QQuickItem *,
const QEvent *) -> std::optional<
bool> {
3128 return std::nullopt;
3131 const auto pos = event->pos().isNull() ? activeFocusItem->mapToScene({}).toPoint() : event->pos();
3132 if (event->pos().isNull())
3133 qCDebug(lcContextMenu) <<
"for QContextMenuEvent, active focus item is" << activeFocusItem <<
"@" << pos;
3134 return eventTargets(item, event, -1, pos, pos, predicate);
3138
3139
3140
3141
3142void QQuickDeliveryAgentPrivate::deliverContextMenuEvent(QContextMenuEvent *event)
3144 skipDelivery.clear();
3145 QList<QQuickItem *> targetItems = contextMenuTargets(rootItem, event);
3146 qCDebug(lcContextMenu) <<
"delivering context menu event" << event <<
"to" << targetItems.size() <<
"target item(s)";
3147 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
3148 for (
auto &item : safeTargetItems) {
3149 qCDebug(lcContextMenu) <<
"- attempting to deliver to" << item;
3153 if (isSubsceneAgent)
3154 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
3156 QCoreApplication::sendEvent(item, event);
3157 if (event->isAccepted())
3162#ifndef QT_NO_DEBUG_STREAM
3165 QDebugStateSaver saver(debug);
3168 debug <<
"QQuickDeliveryAgent(0)";
3172 debug <<
"QQuickDeliveryAgent(";
3173 if (!da->objectName().isEmpty())
3174 debug << da->objectName() <<
' ';
3175 auto root = da->rootItem();
3176 if (Q_LIKELY(root)) {
3177 debug <<
"root=" << root->metaObject()->className();
3178 if (!root->objectName().isEmpty())
3179 debug <<
' ' << root->objectName();
3190#include "moc_qquickdeliveryagent_p.cpp"
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
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)