5#include <QtCore/qdebug.h>
6#include <QtGui/private/qevent_p.h>
7#include <QtGui/private/qeventpoint_p.h>
8#include <QtGui/private/qguiapplication_p.h>
9#include <QtGui/qpa/qplatformtheme.h>
10#include <QtQml/private/qabstractanimationjob_p.h>
11#include <QtQuick/private/qquickdeliveryagent_p_p.h>
12#include <QtQuick/private/qquickhoverhandler_p.h>
13#include <QtQuick/private/qquickpointerhandler_p_p.h>
14#if QT_CONFIG(quick_draganddrop)
15#include <QtQuick/private/qquickdrag_p.h>
17#include <QtQuick/private/qquickitem_p.h>
18#include <QtQuick/private/qquickprofiler_p.h>
19#include <QtQuick/private/qquickrendercontrol_p.h>
20#include <QtQuick/private/qquickwindow_p.h>
22#include <QtCore/qpointer.h>
29Q_STATIC_LOGGING_CATEGORY(lcTouchCmprs,
"qt.quick.touch.compression")
30Q_LOGGING_CATEGORY(lcTouchTarget,
"qt.quick.touch.target")
31Q_LOGGING_CATEGORY(lcMouse,
"qt.quick.mouse")
32Q_STATIC_LOGGING_CATEGORY(lcMouseTarget,
"qt.quick.mouse.target")
33Q_STATIC_LOGGING_CATEGORY(lcTablet,
"qt.quick.tablet")
34Q_LOGGING_CATEGORY(lcPtr,
"qt.quick.pointer")
35Q_STATIC_LOGGING_CATEGORY(lcPtrLoc,
"qt.quick.pointer.localization")
36Q_STATIC_LOGGING_CATEGORY(lcWheelTarget,
"qt.quick.wheel.target")
37Q_LOGGING_CATEGORY(lcHoverTrace,
"qt.quick.hover.trace")
38Q_LOGGING_CATEGORY(lcFocus,
"qt.quick.focus")
39Q_STATIC_LOGGING_CATEGORY(lcContextMenu,
"qt.quick.contextmenu")
41extern 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);
43bool QQuickDeliveryAgentPrivate::subsceneAgentsExist(
false);
44QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentEventDeliveryAgent(
nullptr);
48 static int allowRightClick = -1;
49 if (allowRightClick < 0) {
51 allowRightClick = qEnvironmentVariableIntValue(
"QT_QUICK_ALLOW_SYNTHETIC_RIGHT_CLICK", &ok);
55 return allowRightClick != 0;
58void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type,
const QEventPoint &p,
const QTouchEvent *touchEvent, QMutableSinglePointEvent *mouseEvent)
60 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
61 QMutableSinglePointEvent ret(type, touchEvent->pointingDevice(), p,
62 (type == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton),
63 (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton),
64 touchEvent->modifiers(), Qt::MouseEventSynthesizedByQt);
65 ret.setAccepted(
true);
66 ret.setTimestamp(touchEvent->timestamp());
70 Q_ASSERT(mouseEvent->device() == touchEvent->device());
71 if (Q_UNLIKELY(mouseEvent->device()->type() == QInputDevice::DeviceType::Mouse))
72 qWarning() <<
"Unexpected: synthesized an indistinguishable mouse event" << mouseEvent;
76
77
78bool QQuickDeliveryAgentPrivate::isWithinDoubleClickInterval(ulong timeInterval)
80 return timeInterval <
static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
84
85
86bool QQuickDeliveryAgentPrivate::isWithinDoubleTapDistance(
const QPoint &distanceBetweenPresses)
88 auto square = [](qint64 v) {
return v * v; };
89 return square(distanceBetweenPresses.x()) + square(distanceBetweenPresses.y()) <
90 square(QGuiApplication::styleHints()->touchDoubleTapDistance());
93bool QQuickDeliveryAgentPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp,
const QPoint &newPressPos)
95 const bool doubleClicked = isDeliveringTouchAsMouse() &&
96 isWithinDoubleTapDistance(newPressPos - touchMousePressPos) &&
97 isWithinDoubleClickInterval(newPressEventTimestamp - touchMousePressTimestamp);
99 touchMousePressTimestamp = 0;
101 touchMousePressTimestamp = newPressEventTimestamp;
102 touchMousePressPos = newPressPos;
104 return doubleClicked;
107void QQuickDeliveryAgentPrivate::resetIfDoubleTapPrevented(
const QEventPoint &pressedPoint)
109 if (touchMousePressTimestamp > 0 &&
110 (!isWithinDoubleTapDistance(pressedPoint.globalPosition().toPoint() - touchMousePressPos) ||
111 !isWithinDoubleClickInterval(pressedPoint.timestamp() - touchMousePressTimestamp))) {
112 touchMousePressTimestamp = 0;
113 touchMousePressPos = QPoint();
118
119
120
121
122
123
124
125QPointerEvent *QQuickDeliveryAgentPrivate::eventInDelivery()
const
127 if (eventsInDelivery.isEmpty())
129 return eventsInDelivery.top();
133
134
135
136
137QPointingDevicePrivate::EventPointData *QQuickDeliveryAgentPrivate::mousePointData()
139 if (eventsInDelivery.isEmpty())
141 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(eventsInDelivery.top()->pointingDevice()));
142 return devPriv->pointById(isDeliveringTouchAsMouse() ? touchMouseId : 0);
145void QQuickDeliveryAgentPrivate::cancelTouchMouseSynthesis()
147 qCDebug(lcTouchTarget) <<
"id" << touchMouseId <<
"on" << touchMouseDevice;
149 touchMouseDevice =
nullptr;
152bool QQuickDeliveryAgentPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent)
154 Q_Q(QQuickDeliveryAgent);
155 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
156 auto device = pointerEvent->pointingDevice();
159 if (device->type() == QInputDevice::DeviceType::TouchPad && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
160 qCDebug(lcTouchTarget) << q <<
"skipping delivery of synth-mouse event from" << device;
165 QMutableTouchEvent event;
166 QQuickItemPrivate::get(item)->localizedTouchEvent(pointerEvent,
false, &event);
167 if (!event.points().size())
173 for (
auto &p : event.points()) {
175 if (touchMouseId == -1 && p.state() & QEventPoint::State::Pressed) {
176 QPointF pos = item->mapFromScene(p.scenePosition());
179 if (!item->contains(pos))
182 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << item;
183 QMutableSinglePointEvent mousePress;
184 touchToMouseEvent(QEvent::MouseButtonPress, p, &event, &mousePress);
187 QCoreApplication::sendEvent(item, &mousePress);
188 event.setAccepted(mousePress.isAccepted());
189 if (mousePress.isAccepted()) {
190 touchMouseDevice = device;
191 touchMouseId = p.id();
192 const auto &pt = mousePress.point(0);
193 if (!mousePress.exclusiveGrabber(pt))
194 mousePress.setExclusiveGrabber(pt, item);
196 if (checkIfDoubleTapped(event.timestamp(), p.globalPosition().toPoint())) {
199 QMutableSinglePointEvent mouseDoubleClick;
200 touchToMouseEvent(QEvent::MouseButtonDblClick, p, &event, &mouseDoubleClick);
201 QCoreApplication::sendEvent(item, &mouseDoubleClick);
202 event.setAccepted(mouseDoubleClick.isAccepted());
203 if (!mouseDoubleClick.isAccepted())
204 cancelTouchMouseSynthesis();
212 }
else if (touchMouseDevice == device && p.id() == touchMouseId) {
213 if (p.state() & QEventPoint::State::Updated) {
214 if (touchMousePressTimestamp != 0) {
215 if (!isWithinDoubleTapDistance(p.globalPosition().toPoint() - touchMousePressPos))
216 touchMousePressTimestamp = 0;
218 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
219 QMutableSinglePointEvent me;
220 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
221 QCoreApplication::sendEvent(item, &me);
222 event.setAccepted(me.isAccepted());
224 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << mouseGrabberItem;
225 return event.isAccepted();
230 QMutableSinglePointEvent me;
231 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
232 if (lastMousePosition.isNull())
233 lastMousePosition = me.scenePosition();
234 QPointF last = lastMousePosition;
235 lastMousePosition = me.scenePosition();
237 deliverHoverEvent(me.scenePosition(), last, me.modifiers(), me.timestamp());
240 }
else if (p.state() & QEventPoint::State::Released) {
242 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
243 QMutableSinglePointEvent me;
244 touchToMouseEvent(QEvent::MouseButtonRelease, p, &event, &me);
245 QCoreApplication::sendEvent(item, &me);
247 if (item->acceptHoverEvents() && p.globalPosition() != QGuiApplicationPrivate::lastCursorPosition) {
248 QPointF localMousePos(qInf(), qInf());
249 if (QWindow *w = item->window())
250 localMousePos = item->mapFromScene(w->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition));
251 QMouseEvent mm(QEvent::MouseMove, localMousePos, QGuiApplicationPrivate::lastCursorPosition,
252 Qt::NoButton, Qt::NoButton, event.modifiers());
253 QCoreApplication::sendEvent(item, &mm);
255 if (pointerEvent->exclusiveGrabber(p) == mouseGrabberItem)
256 pointerEvent->setExclusiveGrabber(p,
nullptr);
258 cancelTouchMouseSynthesis();
259 return me.isAccepted();
269
270
271
272
273
274
275
276
277void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber,
bool mouse,
bool touch,
bool cancel)
279 Q_Q(QQuickDeliveryAgent);
280 if (eventsInDelivery.isEmpty()) {
282 for (
auto dev : knownPointingDevices) {
283 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(dev));
284 devPriv->removeGrabber(grabber, cancel);
288 auto eventInDelivery = eventsInDelivery.top();
289 if (Q_LIKELY(mouse) && eventInDelivery) {
290 auto epd = mousePointData();
291 if (epd && epd->exclusiveGrabber == grabber && epd->exclusiveGrabberContext.data() == q) {
292 QQuickItem *oldGrabber = qobject_cast<QQuickItem *>(epd->exclusiveGrabber);
293 qCDebug(lcMouseTarget) <<
"removeGrabber" << oldGrabber <<
"-> null";
294 eventInDelivery->setExclusiveGrabber(epd->eventPoint,
nullptr);
297 if (Q_LIKELY(touch)) {
299 const auto touchDevices = QPointingDevice::devices();
300 for (
auto device : touchDevices) {
301 if (device->type() != QInputDevice::DeviceType::TouchScreen)
303 if (QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(
static_cast<
const QPointingDevice *>(device)))->
304 removeExclusiveGrabber(eventInDelivery, grabber))
308 grabber->touchUngrabEvent();
313
314
315
316
317
318
319
320
321
322
323
324void QQuickDeliveryAgentPrivate::clearGrabbers(QPointerEvent *pointerEvent)
326 if (pointerEvent->isEndEvent()
327 && !(isTabletEvent(pointerEvent)
328 && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
329 || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
330 if (pointerEvent->isSinglePointEvent()) {
331 if (
static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
332 auto &firstPt = pointerEvent->point(0);
333 pointerEvent->setExclusiveGrabber(firstPt,
nullptr);
334 pointerEvent->clearPassiveGrabbers(firstPt);
337 for (
auto &point : pointerEvent->points()) {
338 if (point.state() == QEventPoint::State::Released) {
339 pointerEvent->setExclusiveGrabber(point,
nullptr);
340 pointerEvent->clearPassiveGrabbers(point);
348
349
350
351
352void QQuickDeliveryAgentPrivate::translateTouchEvent(QTouchEvent *touchEvent)
354 for (qsizetype i = 0; i != touchEvent->pointCount(); ++i) {
355 auto &pt = touchEvent->point(i);
356 QMutableEventPoint::setScenePosition(pt, pt.position());
363 const QWindow *focusWindow = QGuiApplication::focusWindow();
364 return win == focusWindow || QQuickRenderControlPrivate::isRenderWindowFor(win, focusWindow) || !focusWindow;
369 QQuickItem *parentItem = item->parentItem();
371 if (parentItem && parentItem->flags() & QQuickItem::ItemIsFocusScope)
372 return findFurthestFocusScopeAncestor(parentItem);
379static inline bool singleWindowOnScreen(QQuickWindow *win)
381 const QWindowList windowList = QGuiApplication::allWindows();
382 for (
int i = 0; i < windowList.count(); i++) {
383 QWindow *ii = windowList.at(i);
386 if (ii->screen() == win->screen())
395
396
397
398
399void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item,
400 Qt::FocusReason reason, FocusOptions options)
402 Q_Q(QQuickDeliveryAgent);
404 Q_ASSERT(scope || item == rootItem);
406 qCDebug(lcFocus) << q <<
"focus" << item <<
"in scope" << scope;
408 qCDebug(lcFocus) <<
" scopeSubFocusItem:" << QQuickItemPrivate::get(scope)->subFocusItem;
410 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) :
nullptr;
411 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
413 QQuickItem *oldActiveFocusItem =
nullptr;
414 QQuickItem *currentActiveFocusItem = activeFocusItem;
415 QQuickItem *newActiveFocusItem =
nullptr;
416 bool sendFocusIn =
false;
418 lastFocusReason = reason;
420 QVarLengthArray<QQuickItem *, 20> changed;
423 if (item == rootItem || scopePrivate->activeFocus) {
424 oldActiveFocusItem = activeFocusItem;
425 if (item->isEnabled()) {
426 newActiveFocusItem = item;
427 while (newActiveFocusItem->isFocusScope()
428 && newActiveFocusItem->scopedFocusItem()
429 && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
430 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
433 newActiveFocusItem = scope;
436 if (oldActiveFocusItem) {
438 QGuiApplication::inputMethod()->commit();
441 activeFocusItem =
nullptr;
443 QQuickItem *afi = oldActiveFocusItem;
444 while (afi && afi != scope) {
445 if (QQuickItemPrivate::get(afi)->activeFocus) {
446 QQuickItemPrivate::get(afi)->activeFocus =
false;
449 afi = afi->parentItem();
454 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
455 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
456 if (oldSubFocusItem) {
457 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
459 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
460 changed << oldSubFocusItem;
463 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
true);
466 if (!(options & DontChangeFocusProperty)) {
467 if (item != rootItem || windowHasFocus(rootItem->window())
471 || singleWindowOnScreen(rootItem->window())
474 itemPrivate->focus =
true;
475 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
480 if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) {
481 activeFocusItem = newActiveFocusItem;
483 QQuickItemPrivate::get(newActiveFocusItem)->activeFocus =
true;
484 changed << newActiveFocusItem;
486 QQuickItem *afi = newActiveFocusItem->parentItem();
487 while (afi && afi != scope) {
488 if (afi->isFocusScope()) {
489 QQuickItemPrivate::get(afi)->activeFocus =
true;
492 afi = afi->parentItem();
494 updateFocusItemTransform();
500 if (oldActiveFocusItem) {
501 QFocusEvent event(QEvent::FocusOut, reason);
502 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
506 if (sendFocusIn && activeFocusItem == newActiveFocusItem) {
507 QFocusEvent event(QEvent::FocusIn, reason);
508 QCoreApplication::sendEvent(newActiveFocusItem, &event);
511 if (activeFocusItem != currentActiveFocusItem)
512 emit rootItem->window()->focusObjectChanged(activeFocusItem);
514 if (!changed.isEmpty())
515 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
516 if (isSubsceneAgent) {
517 auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent;
518 qCDebug(lcFocus) <<
" delegating setFocusInScope to" << da;
526 QQuickItem *ancestorFS = findFurthestFocusScopeAncestor(item);
527 if (ancestorFS != item)
528 options |= QQuickDeliveryAgentPrivate::DontChangeSubFocusItem;
529 QQuickWindowPrivate::get(rootItem->window())->deliveryAgentPrivate()->setFocusInScope(da->rootItem(), item, reason, options);
531 if (oldActiveFocusItem == activeFocusItem)
532 qCDebug(lcFocus) <<
" activeFocusItem remains" << activeFocusItem <<
"in" << q;
534 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
537void QQuickDeliveryAgentPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions options)
540 Q_ASSERT(scope || item == rootItem);
541 Q_Q(QQuickDeliveryAgent);
542 qCDebug(lcFocus) << q <<
"clear focus" << item <<
"in scope" << scope;
544 QQuickItemPrivate *scopePrivate =
nullptr;
546 scopePrivate = QQuickItemPrivate::get(scope);
547 if ( !scopePrivate->subFocusItem )
551 QQuickItem *currentActiveFocusItem = activeFocusItem;
552 QQuickItem *oldActiveFocusItem =
nullptr;
553 QQuickItem *newActiveFocusItem =
nullptr;
555 lastFocusReason = reason;
557 QVarLengthArray<QQuickItem *, 20> changed;
559 Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
562 if (item == rootItem || scopePrivate->activeFocus) {
563 oldActiveFocusItem = activeFocusItem;
564 newActiveFocusItem = scope;
567 QGuiApplication::inputMethod()->commit();
570 activeFocusItem =
nullptr;
572 if (oldActiveFocusItem) {
573 QQuickItem *afi = oldActiveFocusItem;
574 while (afi && afi != scope) {
575 if (QQuickItemPrivate::get(afi)->activeFocus) {
576 QQuickItemPrivate::get(afi)->activeFocus =
false;
579 afi = afi->parentItem();
584 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
585 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
586 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
587 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
589 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
590 changed << oldSubFocusItem;
593 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
false);
595 }
else if (!(options & DontChangeFocusProperty)) {
596 QQuickItemPrivate *priv = QQuickItemPrivate::get(item);
598 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
602 if (newActiveFocusItem) {
603 Q_ASSERT(newActiveFocusItem == scope);
604 activeFocusItem = scope;
605 updateFocusItemTransform();
610 if (oldActiveFocusItem) {
611 QFocusEvent event(QEvent::FocusOut, reason);
612 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
616 if (newActiveFocusItem && activeFocusItem == newActiveFocusItem) {
617 QFocusEvent event(QEvent::FocusIn, reason);
618 QCoreApplication::sendEvent(newActiveFocusItem, &event);
621 QQuickWindow *rootItemWindow = rootItem->window();
622 if (activeFocusItem != currentActiveFocusItem && rootItemWindow)
623 emit rootItemWindow->focusObjectChanged(activeFocusItem);
625 if (!changed.isEmpty())
626 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
627 if (isSubsceneAgent && rootItemWindow) {
628 auto da = QQuickWindowPrivate::get(rootItemWindow)->deliveryAgent;
629 qCDebug(lcFocus) <<
" delegating clearFocusInScope to" << da;
630 QQuickWindowPrivate::get(rootItemWindow)->deliveryAgentPrivate()->clearFocusInScope(da->rootItem(), item, reason, options);
632 if (oldActiveFocusItem == activeFocusItem)
633 qCDebug(lcFocus) <<
"activeFocusItem remains" << activeFocusItem <<
"in" << q;
635 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
638void QQuickDeliveryAgentPrivate::clearFocusObject()
640 if (activeFocusItem == rootItem)
643 clearFocusInScope(rootItem, QQuickItemPrivate::get(rootItem)->subFocusItem, Qt::OtherFocusReason);
646void QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(QQuickItem **items,
int remaining, Qt::FocusReason reason)
648 QPointer<QQuickItem> item(*items);
651 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
653 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
654 itemPrivate->notifiedFocus = itemPrivate->focus;
655 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
656 emit item->focusChanged(itemPrivate->focus);
659 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
660 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
661 itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged,
bool(itemPrivate->activeFocus));
662 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
663 emit item->activeFocusChanged(itemPrivate->activeFocus);
668 notifyFocusChangesRecur(items + 1, remaining - 1, reason);
671bool QQuickDeliveryAgentPrivate::clearHover(ulong timestamp)
673 if (hoverItems.isEmpty())
676 QQuickWindow *window = rootItem->window();
680 const auto globalPos = QGuiApplicationPrivate::lastCursorPosition;
681 const QPointF lastPos = window->mapFromGlobal(globalPos);
682 const auto modifiers = QGuiApplication::keyboardModifiers();
690 for (
auto it = hoverItems.cbegin(); it != hoverItems.cend(); ++it) {
691 if (
const auto &item = it.key()) {
692 deliverHoverEventToItem(item, item->mapFromScene(lastPos), lastPos, lastPos,
693 globalPos, modifiers, timestamp, HoverChange::Clear);
694 Q_ASSERT(([
this, item]{
695 const auto &it2 = std::as_const(hoverItems).find(item);
696 return it2 == hoverItems.cend() || it2.value() == 0;
704void QQuickDeliveryAgentPrivate::updateFocusItemTransform()
707 if (activeFocusItem && QGuiApplication::focusObject() == activeFocusItem) {
708 QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(activeFocusItem);
709 QGuiApplication::inputMethod()->setInputItemTransform(focusPrivate->itemToWindowTransform());
710 QGuiApplication::inputMethod()->setInputItemRectangle(QRectF(0, 0, focusPrivate->width, focusPrivate->height));
711 activeFocusItem->updateInputMethod(Qt::ImInputItemClipRectangle);
717
718
719
720QQuickItem *QQuickDeliveryAgentPrivate::focusTargetItem()
const
723 return activeFocusItem;
726 QQuickItem *targetItem = rootItem;
728 while (targetItem->isFocusScope()
729 && targetItem->scopedFocusItem()
730 && targetItem->scopedFocusItem()->isEnabled()) {
731 targetItem = targetItem->scopedFocusItem();
738
739
740
741
742
743QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(
const QQuickItem *item)
745 if (currentEventDeliveryAgent)
746 return currentEventDeliveryAgent;
748 return QQuickItemPrivate::get(
const_cast<QQuickItem *>(item))->deliveryAgent();
753
754
755
756
757QQuickDeliveryAgent::QQuickDeliveryAgent(QQuickItem *rootItem)
758 : QObject(*
new QQuickDeliveryAgentPrivate(rootItem), rootItem)
762QQuickDeliveryAgent::~QQuickDeliveryAgent()
766QQuickDeliveryAgent::Transform::~Transform()
771
772
773
774QQuickItem *QQuickDeliveryAgent::rootItem()
const
776 Q_D(
const QQuickDeliveryAgent);
781
782
783
784
785QQuickDeliveryAgent::Transform *QQuickDeliveryAgent::sceneTransform()
const
787 Q_D(
const QQuickDeliveryAgent);
788 return d->sceneTransform;
792
793
794
795
796void QQuickDeliveryAgent::setSceneTransform(QQuickDeliveryAgent::Transform *transform)
798 Q_D(QQuickDeliveryAgent);
799 if (d->sceneTransform == transform)
801 qCDebug(lcPtr) <<
this << d->sceneTransform <<
"->" << transform;
802 if (d->sceneTransform)
803 delete d->sceneTransform;
804 d->sceneTransform = transform;
808
809
810
811
812
813
814bool QQuickDeliveryAgent::event(QEvent *ev)
816 Q_D(QQuickDeliveryAgent);
817 d->currentEventDeliveryAgent =
this;
818 auto cleanup = qScopeGuard([d] { d->currentEventDeliveryAgent =
nullptr; });
820 switch (ev->type()) {
821 case QEvent::MouseButtonPress:
822 case QEvent::MouseButtonRelease:
823 case QEvent::MouseButtonDblClick:
824 case QEvent::MouseMove: {
825 QMouseEvent *me =
static_cast<QMouseEvent*>(ev);
826 d->handleMouseEvent(me);
829 case QEvent::HoverEnter:
830 case QEvent::HoverLeave:
831 case QEvent::HoverMove: {
832 QHoverEvent *he =
static_cast<QHoverEvent*>(ev);
833 bool accepted = d->deliverHoverEvent(he->scenePosition(),
834 he->points().first().sceneLastPosition(),
835 he->modifiers(), he->timestamp());
836 d->lastMousePosition = he->scenePosition();
837 he->setAccepted(accepted);
839 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(d->sceneTransform ?
840 d->sceneTransform->map(he->scenePosition()) : he->scenePosition(), d->rootItem);
844 case QEvent::TouchBegin:
845 case QEvent::TouchUpdate:
846 case QEvent::TouchEnd: {
847 QTouchEvent *touch =
static_cast<QTouchEvent*>(ev);
848 d->handleTouchEvent(touch);
849 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
856 case QEvent::TouchCancel:
858 return d->deliverTouchCancelEvent(
static_cast<QTouchEvent*>(ev));
860 case QEvent::Enter: {
863 QEnterEvent *enter =
static_cast<QEnterEvent*>(ev);
864 const auto scenePos = enter->scenePosition();
865 qCDebug(lcHoverTrace) <<
this <<
"sending hover event due to QEnterEvent" << enter;
866 bool accepted = d->deliverHoverEvent(scenePos,
867 enter->points().first().sceneLastPosition(),
868 enter->modifiers(), enter->timestamp());
869 d->lastMousePosition = scenePos;
871 Q_ASSERT(enter->scenePosition() == scenePos);
872 enter->setAccepted(accepted);
874 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(enter->scenePosition(), d->rootItem);
880 d->lastMousePosition = QPointF();
882#if QT_CONFIG(quick_draganddrop)
883 case QEvent::DragEnter:
884 case QEvent::DragLeave:
885 case QEvent::DragMove:
887 d->deliverDragEvent(d->dragGrabber, ev);
890 case QEvent::FocusAboutToChange:
892 if (d->activeFocusItem)
893 qGuiApp->inputMethod()->commit();
896#if QT_CONFIG(gestures)
897 case QEvent::NativeGesture:
898 d->deliverSinglePointEventUntilAccepted(
static_cast<QPointerEvent *>(ev));
901 case QEvent::ShortcutOverride:
902 d->deliverKeyEvent(
static_cast<QKeyEvent *>(ev));
904 case QEvent::InputMethod:
905 case QEvent::InputMethodQuery:
907 QQuickItem *target = d->focusTargetItem();
909 QCoreApplication::sendEvent(target, ev);
912#if QT_CONFIG(wheelevent)
913 case QEvent::Wheel: {
914 auto event =
static_cast<QWheelEvent *>(ev);
915 qCDebug(lcMouse) << event;
918 if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate)
922 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
923 event->angleDelta().x(), event->angleDelta().y());
924 d->deliverSinglePointEventUntilAccepted(event);
925 d->lastWheelEventAccepted = event->isAccepted();
929#if QT_CONFIG(tabletevent)
930 case QEvent::TabletPress:
931 case QEvent::TabletMove:
932 case QEvent::TabletRelease:
934 auto *tabletEvent =
static_cast<QTabletEvent *>(ev);
935 d->deliverPointerEvent(tabletEvent);
937 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(tabletEvent->scenePosition(), d->rootItem);
942#ifndef QT_NO_CONTEXTMENU
943 case QEvent::ContextMenu:
944 d->deliverContextMenuEvent(
static_cast<QContextMenuEvent *>(ev));
948 Q_ASSERT(
static_cast<QTimerEvent *>(ev)->timerId() == d->frameSynchronousDelayTimer.timerId());
949 d->frameSynchronousDelayTimer.stop();
950 d->flushFrameSynchronousEvents(d->rootItem->window());
959void QQuickDeliveryAgentPrivate::deliverKeyEvent(QKeyEvent *e)
961 if (activeFocusItem) {
962 const bool keyPress = (e->type() == QEvent::KeyPress);
964 case QEvent::KeyPress:
965 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(), e->modifiers());
967 case QEvent::KeyRelease:
968 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(), e->modifiers());
974 QQuickItem *item = activeFocusItem;
977 if (keyPress && e->spontaneous() ==
false)
978 qt_sendShortcutOverrideEvent(item, e->timestamp(),
979 e->key(), e->modifiers(), e->text(),
980 e->isAutoRepeat(), e->count());
983 Q_ASSERT(e->type() != QEvent::ShortcutOverride || !e->isAccepted());
984 if (e->type() != QEvent::ShortcutOverride)
986 QCoreApplication::sendEvent(item, e);
987 }
while (!e->isAccepted() && (item = item->parentItem()));
991QQuickDeliveryAgentPrivate::QQuickDeliveryAgentPrivate(QQuickItem *root) :
995 isSubsceneAgent(!qmlobject_cast<QQuickRootItem *>(rootItem))
997#if QT_CONFIG(quick_draganddrop)
998 dragGrabber =
new QQuickDragGrabber;
1000 if (isSubsceneAgent)
1001 subsceneAgentsExist =
true;
1002 const auto interval = qEnvironmentVariableIntegerValue(
"QT_QUICK_FRAME_SYNCHRONOUS_HOVER_INTERVAL");
1003 if (interval.has_value()) {
1004 qCDebug(lcHoverTrace) <<
"frame-synchronous hover interval" << interval;
1005 frameSynchronousHoverInterval =
int(interval.value());
1007 if (frameSynchronousHoverInterval > 0)
1008 frameSynchronousHoverTimer.start();
1011QQuickDeliveryAgentPrivate::~QQuickDeliveryAgentPrivate()
1013#if QT_CONFIG(quick_draganddrop)
1015 dragGrabber =
nullptr;
1017 delete sceneTransform;
1021
1022
1023
1024
1025
1026
1027QPointerEvent *QQuickDeliveryAgentPrivate::clonePointerEvent(QPointerEvent *event, std::optional<QPointF> transformedLocalPos)
1029 QPointerEvent *ret = event->clone();
1030 QEventPoint &point = ret->point(0);
1031 QMutableEventPoint::detach(point);
1032 QMutableEventPoint::setTimestamp(point, event->timestamp());
1033 if (transformedLocalPos)
1034 QMutableEventPoint::setPosition(point, *transformedLocalPos);
1039void QQuickDeliveryAgentPrivate::deliverToPassiveGrabbers(
const QList<QPointer <QObject> > &passiveGrabbers,
1040 QPointerEvent *pointerEvent)
1042 const QList<QObject *> &eventDeliveryTargets =
1043 QQuickPointerHandlerPrivate::deviceDeliveryTargets(pointerEvent->device());
1044 QVarLengthArray<std::pair<QQuickItem *,
bool>, 4> sendFilteredPointerEventResult;
1045 hasFiltered.clear();
1046 for (QObject *grabberObject : passiveGrabbers) {
1048 if (Q_UNLIKELY(!grabberObject))
1051 if (QQuickPointerHandler *handler = qobject_cast<QQuickPointerHandler *>(grabberObject)) {
1052 if (handler && !eventDeliveryTargets.contains(handler)) {
1053 bool alreadyFiltered =
false;
1054 QQuickItem *par = handler->parentItem();
1057 auto it = std::find_if(sendFilteredPointerEventResult.begin(), sendFilteredPointerEventResult.end(),
1058 [par](
const std::pair<QQuickItem *,
bool> &pair) {
return pair.first == par; });
1059 if (it != sendFilteredPointerEventResult.end()) {
1062 alreadyFiltered = it->second;
1064 alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par);
1065 sendFilteredPointerEventResult << std::make_pair(par, alreadyFiltered);
1067 if (!alreadyFiltered) {
1069 localizePointerEvent(pointerEvent, par);
1070 handler->handlePointerEvent(pointerEvent);
1073 }
else if (QQuickItem *grabberItem =
static_cast<QQuickItem *>(grabberObject)) {
1075 if (QQuickItem *excGrabber =
static_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(pointerEvent->point(0)))) {
1076 if ((isMouseEvent(pointerEvent) && excGrabber->keepMouseGrab())
1077 || (isTouchEvent(pointerEvent) && excGrabber->keepTouchGrab())) {
1081 localizePointerEvent(pointerEvent, grabberItem);
1082 QCoreApplication::sendEvent(grabberItem, pointerEvent);
1083 pointerEvent->accept();
1088bool QQuickDeliveryAgentPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1089 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1090 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp)
1092 QHoverEvent hoverEvent(type, scenePos, globalPos, lastScenePos, modifiers);
1093 hoverEvent.setTimestamp(timestamp);
1094 hoverEvent.setAccepted(
true);
1095 QEventPoint &point = hoverEvent.point(0);
1096 QMutableEventPoint::setPosition(point, localPos);
1097 if (Q_LIKELY(item->window()))
1098 QMutableEventPoint::setGlobalLastPosition(point, item->window()->mapToGlobal(lastScenePos));
1100 hasFiltered.clear();
1101 if (sendFilteredMouseEvent(&hoverEvent, item, item->parentItem()))
1104 QCoreApplication::sendEvent(item, &hoverEvent);
1106 return hoverEvent.isAccepted();
1110
1111
1112
1113
1115bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
1116 const QPointF &scenePos,
const QPointF &lastScenePos,
1117 Qt::KeyboardModifiers modifiers, ulong timestamp)
1135 const bool subtreeHoverEnabled = QQuickItemPrivate::get(rootItem)->subtreeHoverEnabled;
1136 const bool itemsWasHovered = !hoverItems.isEmpty();
1138 if (!subtreeHoverEnabled && !itemsWasHovered)
1143 if (subtreeHoverEnabled) {
1144 hoveredLeafItemFound =
false;
1145 QQuickPointerHandlerPrivate::deviceDeliveryTargets(QPointingDevice::primaryPointingDevice()).clear();
1146 deliverHoverEventRecursive(rootItem, scenePos, scenePos, lastScenePos,
1147 rootItem->mapToGlobal(scenePos), modifiers, timestamp);
1151 for (
auto it = hoverItems.begin(); it != hoverItems.end();) {
1152 const auto &[item, hoverId] = *it;
1153 if (hoverId == currentHoverId) {
1160 if (item && hoverId != 0)
1161 deliverHoverEventToItem(item, item->mapFromScene(scenePos), scenePos, lastScenePos,
1162 QGuiApplicationPrivate::lastCursorPosition, modifiers, timestamp, HoverChange::Clear);
1163 it = hoverItems.erase(it);
1167 const bool itemsAreHovered = !hoverItems.isEmpty();
1168 return itemsWasHovered || itemsAreHovered;
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(QQuickItem *item,
1208 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
const QPointF &globalPos,
1209 Qt::KeyboardModifiers modifiers, ulong timestamp)
1211 const QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1212 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1213 const bool hadChildrenChanged = itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged;
1215 for (
int ii = children.size() - 1; ii >= 0; --ii) {
1219 if (!hadChildrenChanged && Q_UNLIKELY(itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged))
1221 QQuickItem *child = children.at(ii);
1222 const QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
1224 if (!child->isVisible() || childPrivate->culled)
1226 if (!childPrivate->subtreeHoverEnabled)
1229 QTransform childToParent;
1230 childPrivate->itemToParentTransform(&childToParent);
1231 const QPointF childLocalPos = childToParent.inverted().map(localPos);
1236 if (childPrivate->effectivelyClipsEventHandlingChildren() &&
1237 !childPrivate->eventHandlingBounds().contains(childLocalPos)) {
1238#ifdef QT_BUILD_INTERNAL
1239 ++QQuickItemPrivate::effectiveClippingSkips_counter;
1245 const bool accepted = deliverHoverEventRecursive(child, childLocalPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1250 if (hoveredLeafItemFound) {
1258 return deliverHoverEventToItem(item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp, HoverChange::Set);
1262
1263
1264
1265
1266
1267
1268
1269bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1270 QQuickItem *item,
const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1271 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp, HoverChange hoverChange)
1273 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1274 const bool isHovering = item->contains(localPos);
1275 const auto hoverItemIterator = hoverItems.find(item);
1276 const bool wasHovering = hoverItemIterator != hoverItems.end() && hoverItemIterator.value() != 0;
1278 qCDebug(lcHoverTrace) <<
"item:" << item <<
"scene pos:" << scenePos <<
"localPos:" << localPos
1279 <<
"wasHovering:" << wasHovering <<
"isHovering:" << isHovering;
1281 bool accepted =
false;
1286 if (itemPrivate->hoverEnabled && isHovering && hoverChange == HoverChange::Set) {
1291 hoveredLeafItemFound =
true;
1292 if (hoverItemIterator != hoverItems.end())
1293 hoverItemIterator.value() = currentHoverId;
1295 hoverItems[item] = currentHoverId;
1298 accepted = sendHoverEvent(QEvent::HoverMove, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1300 accepted = sendHoverEvent(QEvent::HoverEnter, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1301 }
else if (wasHovering) {
1303 hoverItemIterator.value() = 0;
1304 sendHoverEvent(QEvent::HoverLeave, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1307 if (!itemPrivate->hasPointerHandlers())
1317 if (hoverChange == HoverChange::Clear) {
1319 QHoverEvent hoverEvent(QEvent::HoverLeave, scenePos, globalPos, lastScenePos, modifiers);
1320 hoverEvent.setTimestamp(timestamp);
1322 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1323 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1324 if (!hh->isHovered())
1326 hoverEvent.setAccepted(
true);
1327 QCoreApplication::sendEvent(hh, &hoverEvent);
1331 QMouseEvent hoverEvent(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, Qt::NoButton, modifiers);
1332 hoverEvent.setTimestamp(timestamp);
1334 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1335 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1338 hoverEvent.setAccepted(
true);
1339 hh->handlePointerEvent(&hoverEvent);
1340 if (hh->isHovered()) {
1343 hoveredLeafItemFound =
true;
1344 if (hoverItemIterator != hoverItems.end())
1345 hoverItemIterator.value() = currentHoverId;
1347 hoverItems[item] = currentHoverId;
1348 if (hh->isBlocking()) {
1349 qCDebug(lcHoverTrace) <<
"skipping rest of hover delivery due to blocking" << hh;
1363bool QQuickDeliveryAgentPrivate::deliverSinglePointEventUntilAccepted(QPointerEvent *event)
1365 Q_ASSERT(event->points().size() == 1);
1366 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
1367 QEventPoint &point = event->point(0);
1368 QList<QQuickItem *> targetItems = pointerTargets(rootItem, event, point,
false,
false);
1369 point.setAccepted(
false);
1374 for (
const auto &passiveGrabber : event->passiveGrabbers(point)) {
1375 if (
auto *grabberItem = qobject_cast<QQuickItem *>(passiveGrabber)) {
1376 if (targetItems.contains(grabberItem))
1378 localizePointerEvent(event, grabberItem);
1379 QCoreApplication::sendEvent(grabberItem, event);
1386 for (QQuickItem *item : targetItems) {
1387 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1388 localizePointerEvent(event, item);
1390 itemPrivate->handlePointerEvent(event);
1391 if (point.isAccepted())
1394 QCoreApplication::sendEvent(item, event);
1395 if (event->isAccepted()) {
1396 qCDebug(lcWheelTarget) << event <<
"->" << item;
1404bool QQuickDeliveryAgentPrivate::deliverTouchCancelEvent(QTouchEvent *event)
1406 qCDebug(lcTouch) << event;
1411 const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(event->pointingDevice()))->
1412 sendTouchCancelEvent(event);
1414 cancelTouchMouseSynthesis();
1419void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent()
1424 std::unique_ptr<QTouchEvent> e(std::move(delayedTouch));
1425 qCDebug(lcTouchCmprs) <<
"delivering" << e.get();
1426 compressedTouchCount = 0;
1427 deliverPointerEvent(e.get());
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
1442 Q_Q(QQuickDeliveryAgent);
1443 qCDebug(lcFocus) <<
"deactivated" << win->title();
1444 const auto inputDevices = QInputDevice::devices();
1445 for (
auto device : inputDevices) {
1446 if (
auto pointingDevice = qobject_cast<
const QPointingDevice *>(device)) {
1447 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(pointingDevice));
1448 for (
auto epd : devPriv->activePoints.values()) {
1449 if (!epd.exclusiveGrabber.isNull()) {
1450 bool relevant =
false;
1451 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(epd.exclusiveGrabber.data()))
1452 relevant = (item->window() == win);
1453 else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(epd.exclusiveGrabber.data())) {
1454 if (handler->parentItem())
1455 relevant = (handler->parentItem()->window() == win && epd.exclusiveGrabberContext.data() == q);
1462 devPriv->setExclusiveGrabber(
nullptr, epd.eventPoint,
nullptr);
1471void QQuickDeliveryAgentPrivate::handleWindowHidden(QQuickWindow *win)
1473 qCDebug(lcFocus) <<
"hidden" << win->title();
1475 lastMousePosition = QPointF();
1478bool QQuickDeliveryAgentPrivate::allUpdatedPointsAccepted(
const QPointerEvent *ev)
1480 for (
auto &point : ev->points()) {
1481 if (point.state() != QEventPoint::State::Pressed && !point.isAccepted())
1488
1489
1490
1491
1492
1493void QQuickDeliveryAgentPrivate::localizePointerEvent(QPointerEvent *ev,
const QQuickItem *dest)
1495 for (
int i = 0; i < ev->pointCount(); ++i) {
1496 auto &point = ev->point(i);
1497 QMutableEventPoint::setPosition(point, dest->mapFromScene(point.scenePosition()));
1498 qCDebug(lcPtrLoc) << ev->type() <<
"@" << point.scenePosition() <<
"to"
1499 << dest <<
"@" << dest->mapToScene(QPointF()) <<
"->" << point;
1503QList<QObject *> QQuickDeliveryAgentPrivate::exclusiveGrabbers(QPointerEvent *ev)
1505 QList<QObject *> result;
1506 for (
const QEventPoint &point : ev->points()) {
1507 if (QObject *grabber = ev->exclusiveGrabber(point)) {
1508 if (!result.contains(grabber))
1515bool QQuickDeliveryAgentPrivate::anyPointGrabbed(
const QPointerEvent *ev)
1517 for (
const QEventPoint &point : ev->points()) {
1518 if (ev->exclusiveGrabber(point) || !ev->passiveGrabbers(point).isEmpty())
1524bool QQuickDeliveryAgentPrivate::allPointsGrabbed(
const QPointerEvent *ev)
1526 for (
const auto &point : ev->points()) {
1527 if (!ev->exclusiveGrabber(point) && ev->passiveGrabbers(point).isEmpty())
1533bool QQuickDeliveryAgentPrivate::isMouseEvent(
const QPointerEvent *ev)
1535 switch (ev->type()) {
1536 case QEvent::MouseButtonPress:
1537 case QEvent::MouseButtonRelease:
1538 case QEvent::MouseButtonDblClick:
1539 case QEvent::MouseMove:
1546bool QQuickDeliveryAgentPrivate::isMouseOrWheelEvent(
const QPointerEvent *ev)
1548 return isMouseEvent(ev) || ev->type() == QEvent::Wheel;
1551bool QQuickDeliveryAgentPrivate::isHoverEvent(
const QPointerEvent *ev)
1553 switch (ev->type()) {
1554 case QEvent::HoverEnter:
1555 case QEvent::HoverMove:
1556 case QEvent::HoverLeave:
1563bool QQuickDeliveryAgentPrivate::isTouchEvent(
const QPointerEvent *ev)
1565 switch (ev->type()) {
1566 case QEvent::TouchBegin:
1567 case QEvent::TouchUpdate:
1568 case QEvent::TouchEnd:
1569 case QEvent::TouchCancel:
1576bool QQuickDeliveryAgentPrivate::isTabletEvent(
const QPointerEvent *ev)
1578#if QT_CONFIG(tabletevent)
1579 switch (ev->type()) {
1580 case QEvent::TabletPress:
1581 case QEvent::TabletMove:
1582 case QEvent::TabletRelease:
1583 case QEvent::TabletEnterProximity:
1584 case QEvent::TabletLeaveProximity:
1595bool QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(
const QPointerEvent *ev)
1597 const auto devType = ev->device()->type();
1598 return devType == QInputDevice::DeviceType::Mouse ||
1599 devType == QInputDevice::DeviceType::TouchPad;
1602bool QQuickDeliveryAgentPrivate::isSynthMouse(
const QPointerEvent *ev)
1604 return (!isEventFromMouseOrTouchpad(ev) && isMouseEvent(ev));
1608
1609
1610
1611bool QQuickDeliveryAgentPrivate::isSinglePointDevice(
const QInputDevice *dev)
1613 switch (dev->type()) {
1614 case QInputDevice::DeviceType::Mouse:
1615 case QInputDevice::DeviceType::TouchPad:
1616 case QInputDevice::DeviceType::Puck:
1617 case QInputDevice::DeviceType::Stylus:
1618 case QInputDevice::DeviceType::Airbrush:
1620 case QInputDevice::DeviceType::TouchScreen:
1621 case QInputDevice::DeviceType::Keyboard:
1622 case QInputDevice::DeviceType::Unknown:
1623 case QInputDevice::DeviceType::AllDevices:
1629QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(
const QInputDevice *device)
1631 QInputDevicePrivate *devPriv = QInputDevicePrivate::get(
const_cast<QInputDevice *>(device));
1632 if (devPriv->qqExtra)
1633 return static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1634 auto extra =
new QQuickPointingDeviceExtra;
1635 devPriv->qqExtra = extra;
1636 QObject::connect(device, &QObject::destroyed, [devPriv]() {
1637 delete static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1638 devPriv->qqExtra =
nullptr;
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
1671 if (isSubsceneAgent)
1674 QEventPoint::States states = event->touchPointStates();
1675 if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
1676 qCDebug(lcTouchCmprs) <<
"no compression" << event;
1681 if (!delayedTouch) {
1682 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points()));
1683 delayedTouch->setTimestamp(event->timestamp());
1684 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1685 auto &tp = delayedTouch->point(i);
1686 QMutableEventPoint::detach(tp);
1688 ++compressedTouchCount;
1689 qCDebug(lcTouchCmprs) <<
"delayed" << compressedTouchCount << delayedTouch.get();
1690 if (QQuickWindow *window = rootItem->window())
1691 window->maybeUpdate();
1696 if (delayedTouch->type() == event->type() &&
1697 delayedTouch->device() == event->device() &&
1698 delayedTouch->modifiers() == event->modifiers() &&
1699 delayedTouch->pointCount() == event->pointCount())
1702 bool mismatch =
false;
1704 auto tpts = event->points();
1705 for (qsizetype i = 0; i < event->pointCount(); ++i) {
1706 const auto &tp = tpts.at(i);
1707 const auto &tpDelayed = delayedTouch->point(i);
1708 if (tp.id() != tpDelayed.id()) {
1713 if (tpDelayed.state() == QEventPoint::State::Updated && tp.state() == QEventPoint::State::Stationary)
1714 QMutableEventPoint::setState(tpts[i], QEventPoint::State::Updated);
1721 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts));
1722 delayedTouch->setTimestamp(event->timestamp());
1723 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1724 auto &tp = delayedTouch->point(i);
1725 QMutableEventPoint::detach(tp);
1727 ++compressedTouchCount;
1728 qCDebug(lcTouchCmprs) <<
"coalesced" << compressedTouchCount << delayedTouch.get();
1729 if (QQuickWindow *window = rootItem->window())
1730 window->maybeUpdate();
1736 deliverDelayedTouchEvent();
1737 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(),
1738 event->modifiers(), event->points()));
1739 delayedTouch->setTimestamp(event->timestamp());
1747void QQuickDeliveryAgentPrivate::handleTouchEvent(QTouchEvent *event)
1749 Q_Q(QQuickDeliveryAgent);
1750 translateTouchEvent(event);
1752 if (event->pointCount()) {
1753 auto &point = event->point(0);
1754 if (point.state() == QEventPoint::State::Released) {
1755 lastMousePosition = QPointF();
1757 lastMousePosition = point.position();
1761 qCDebug(lcTouch) << q << event;
1763 static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet(
"QML_NO_TOUCH_COMPRESSION");
1765 if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) {
1766 deliverPointerEvent(event);
1770 if (!compressTouchEvent(event)) {
1772 deliverDelayedTouchEvent();
1773 qCDebug(lcTouchCmprs) <<
"resuming delivery" << event;
1775 deliverPointerEvent(event);
1780
1781
1782void QQuickDeliveryAgentPrivate::handleMouseEvent(QMouseEvent *event)
1784 Q_Q(QQuickDeliveryAgent);
1788 if (event->source() == Qt::MouseEventSynthesizedBySystem &&
1789 !(event->button() == Qt::RightButton && allowSyntheticRightClick())) {
1793 qCDebug(lcMouse) << q << event;
1795 switch (event->type()) {
1796 case QEvent::MouseButtonPress:
1797 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
1799 deliverPointerEvent(event);
1801 case QEvent::MouseButtonRelease:
1802 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
1804 deliverPointerEvent(event);
1805#if QT_CONFIG(cursor)
1806 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1809 case QEvent::MouseButtonDblClick:
1810 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1811 event->button(), event->buttons());
1812 deliverPointerEvent(event);
1814 case QEvent::MouseMove: {
1815 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
1816 event->position().x(), event->position().y());
1818 const QPointF last = lastMousePosition.isNull() ? event->scenePosition() : lastMousePosition;
1819 lastMousePosition = event->scenePosition();
1820 qCDebug(lcHoverTrace) << q << event <<
"mouse pos" << last <<
"->" << lastMousePosition;
1821 if (!event->points().size() || !event->exclusiveGrabber(event->point(0))) {
1822 bool accepted = deliverHoverEvent(event->scenePosition(), last, event->modifiers(), event->timestamp());
1823 event->setAccepted(accepted);
1825 deliverPointerEvent(event);
1826#if QT_CONFIG(cursor)
1828 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853void QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents(QQuickWindow *win)
1855 Q_Q(QQuickDeliveryAgent);
1856 QQuickDeliveryAgent *deliveringAgent = QQuickDeliveryAgentPrivate::currentEventDeliveryAgent;
1857 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = q;
1860 deliverDelayedTouchEvent();
1864 QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
1865 if (ut && ut->hasStartAnimationPending())
1866 ut->startAnimations();
1871#if !defined(Q_OS_WEBOS)
1881 if (frameSynchronousHoverInterval >= 0) {
1882 const bool timerActive = frameSynchronousHoverInterval > 0;
1883 const bool timerMature = frameSynchronousHoverTimer.elapsed() >= frameSynchronousHoverInterval;
1884 if (timerActive && !timerMature) {
1885 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery delayed: elapsed"
1886 << frameSynchronousHoverTimer.elapsed() <<
"<" << frameSynchronousHoverInterval;
1887 if (!frameSynchronousDelayTimer.isActive())
1888 frameSynchronousDelayTimer.start(frameSynchronousHoverInterval - frameSynchronousHoverTimer.elapsed(), q);
1889 }
else if (!win->mouseGrabberItem() && !lastMousePosition.isNull() &&
1890 (timerMature || QQuickWindowPrivate::get(win)->dirtyItemList)) {
1891 frameSynchronousDelayTimer.stop();
1892 qCDebug(lcHoverTrace) << q <<
"delivering frame-sync hover to root @" << lastMousePosition
1893 <<
"after elapsed time" << frameSynchronousHoverTimer.elapsed();
1894 if (deliverHoverEvent(lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0)) {
1895#if QT_CONFIG(cursor)
1896 QQuickWindowPrivate::get(rootItem->window())->updateCursor(
1897 sceneTransform ? sceneTransform->map(lastMousePosition) : lastMousePosition, rootItem);
1902 frameSynchronousHoverTimer.restart();
1903 ++frameSynchronousHover_counter;
1904 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery done: round" << frameSynchronousHover_counter;
1910 if (Q_UNLIKELY(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent &&
1911 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent != q))
1912 qCWarning(lcPtr,
"detected interleaved frame-sync and actual events");
1913 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveringAgent;
1917
1918
1919
1920
1921
1922
1923
1924void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition,
1925 const QPointerEvent *event,
const QEventPoint &point)
1927 Q_Q(QQuickDeliveryAgent);
1928 const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
1929 transition == QPointingDevice::GrabTransition::GrabPassive);
1932 if (
auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
1933 if (handler->parentItem()) {
1934 auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
1935 if (itemPriv->deliveryAgent() == q) {
1936 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1937 const_cast<QEventPoint &>(point));
1942 if (isSubsceneAgent && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
1943 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
1945 }
else if (!isSubsceneAgent) {
1946 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1947 const_cast<QEventPoint &>(point));
1949 }
else if (
auto *grabberItem = qmlobject_cast<QQuickItem *>(grabber)) {
1950 switch (transition) {
1951 case QPointingDevice::CancelGrabExclusive:
1952 case QPointingDevice::UngrabExclusive:
1953 if (isDeliveringTouchAsMouse() || isSinglePointDevice(point.device())) {
1956 QMutableSinglePointEvent e(QEvent::UngrabMouse, point.device(), point);
1957 hasFiltered.clear();
1958 if (!sendFilteredMouseEvent(&e, grabberItem, grabberItem->parentItem())) {
1959 lastUngrabbed = grabberItem;
1960 grabberItem->mouseUngrabEvent();
1965 bool allReleasedOrCancelled =
true;
1966 if (transition == QPointingDevice::UngrabExclusive && event) {
1967 for (
const auto &pt : event->points()) {
1968 if (pt.state() != QEventPoint::State::Released) {
1969 allReleasedOrCancelled =
false;
1974 if (allReleasedOrCancelled)
1975 grabberItem->touchUngrabEvent();
1981 auto *itemPriv = QQuickItemPrivate::get(grabberItem);
1984 if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
1985 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
1988 if (currentEventDeliveryAgent == q && event && event->device()) {
1989 switch (transition) {
1990 case QPointingDevice::GrabPassive: {
1991 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
1993 QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q);
1994 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
1996 case QPointingDevice::GrabExclusive: {
1997 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
1999 epd->exclusiveGrabberContext = q;
2000 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2002 case QPointingDevice::CancelGrabExclusive:
2003 case QPointingDevice::UngrabExclusive:
2006 case QPointingDevice::UngrabPassive:
2007 case QPointingDevice::CancelGrabPassive:
2010 case QPointingDevice::OverrideGrabPassive:
2018
2019
2020
2021
2022
2023
2024
2025
2026void QQuickDeliveryAgentPrivate::ensureDeviceConnected(
const QPointingDevice *dev)
2028 Q_Q(QQuickDeliveryAgent);
2029 if (knownPointingDevices.contains(dev))
2031 knownPointingDevices.append(dev);
2032 connect(dev, &QPointingDevice::grabChanged,
this, &QQuickDeliveryAgentPrivate::onGrabChanged);
2033 QObject::connect(dev, &QObject::destroyed, q, [
this, dev] {
this->knownPointingDevices.removeAll(dev);});
2037
2038
2039
2040
2041
2042
2043void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
2045 Q_Q(QQuickDeliveryAgent);
2046 if (isTabletEvent(event))
2047 qCDebug(lcTablet) << q << event;
2052 ++pointerEventRecursionGuard;
2053 eventsInDelivery.push(event);
2059 QVarLengthArray<QPointF, 16> originalScenePositions;
2060 if (sceneTransform) {
2061 originalScenePositions.resize(event->pointCount());
2062 for (
int i = 0; i < event->pointCount(); ++i) {
2063 auto &pt = event->point(i);
2064 originalScenePositions[i] = pt.scenePosition();
2065 QMutableEventPoint::setScenePosition(pt, sceneTransform->map(pt.scenePosition()));
2066 qCDebug(lcPtrLoc) << q << event->type() << pt.id() <<
"transformed scene pos" << pt.scenePosition();
2068 }
else if (isSubsceneAgent) {
2069 qCDebug(lcPtrLoc) << q << event->type() <<
"no scene transform set";
2072 skipDelivery.clear();
2073 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
2075 qCDebug(lcPtr) << q <<
"delivering with" << sceneTransform << event;
2077 qCDebug(lcPtr) << q <<
"delivering" << event;
2078 for (
int i = 0; i < event->pointCount(); ++i)
2079 event->point(i).setAccepted(
false);
2081 if (event->isBeginEvent()) {
2082 ensureDeviceConnected(event->pointingDevice());
2083 if (event->type() == QEvent::MouseButtonPress && rootItem->window()
2084 &&
static_cast<QSinglePointEvent *>(event)->button() == Qt::RightButton) {
2085 QQuickWindowPrivate::get(rootItem->window())->rmbContextMenuEventEnabled =
true;
2087 if (!deliverPressOrReleaseEvent(event))
2088 event->setAccepted(
false);
2091 auto isHoveringMoveEvent = [](QPointerEvent *event) ->
bool {
2092 if (event->type() == QEvent::MouseMove) {
2093 const auto *spe =
static_cast<
const QSinglePointEvent *>(event);
2094 if (spe->button() == Qt::NoButton && spe->buttons() == Qt::NoButton)
2101
2102
2103
2104
2105
2106
2107
2108
2109 if (!allUpdatedPointsAccepted(event) && !isHoveringMoveEvent(event))
2110 deliverUpdatedPoints(event);
2111 if (event->isEndEvent())
2112 deliverPressOrReleaseEvent(event,
true);
2116 if (isTouchEvent(event) && touchMouseId >= 0) {
2117 if (
static_cast<QTouchEvent *>(event)->touchPointStates() == QEventPoint::State::Released) {
2118 cancelTouchMouseSynthesis();
2120 auto touchMousePoint = event->pointById(touchMouseId);
2121 if (touchMousePoint && touchMousePoint->state() == QEventPoint::State::Released)
2122 cancelTouchMouseSynthesis();
2126 eventsInDelivery.pop();
2127 if (sceneTransform) {
2128 for (
int i = 0; i < event->pointCount(); ++i)
2129 QMutableEventPoint::setScenePosition(event->point(i), originalScenePositions.at(i));
2131 --pointerEventRecursionGuard;
2132 lastUngrabbed =
nullptr;
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2173QList<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
const QEvent *event,
int pointId,
2174 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate)
const
2176 QList<QQuickItem *> targets;
2177 auto itemPrivate = QQuickItemPrivate::get(item);
2182 if (item != rootItem && !itemPrivate->eventHandlingBounds().contains(localPos) &&
2183 itemPrivate->effectivelyClipsEventHandlingChildren()) {
2184 qCDebug(lcPtrLoc) <<
"skipping because" << localPos <<
"is outside rectangular bounds of" << item;
2190 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2195 Q_ASSERT(event->isPointerEvent());
2196 QPointerEvent *pev =
const_cast<QPointerEvent *>(
static_cast<
const QPointerEvent *>(event));
2197 QEventPoint *point = pev->pointById(pointId);
2199 QMutableEventPoint::setPosition(*point, localPos);
2201 const std::optional<
bool> override = predicate(item, event);
2202 const bool relevant = override.has_value() ? override.value()
2203 : item == rootItem || item->contains(localPos);
2205 auto it = std::lower_bound(children.begin(), children.end(), 0,
2206 [](
auto lhs,
auto rhs) ->
bool {
return lhs->z() < rhs; });
2207 children.insert(it, item);
2212 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2213 QQuickItem *child = children.at(ii);
2214 auto childPrivate = QQuickItemPrivate::get(child);
2215 if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
2216 (child != item && childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
2219 if (child == item) {
2222 QTransform childToParent;
2223 childPrivate->itemToParentTransform(&childToParent);
2224 const QPointF childLocalPos = childToParent.inverted().map(localPos);
2225 targets << eventTargets(child, event, pointId, childLocalPos, scenePos, predicate);
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261QList<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *item,
const QPointerEvent *event,
const QEventPoint &point,
2262 bool checkMouseButtons,
bool checkAcceptsTouch)
const
2264 auto predicate = [point, checkMouseButtons, checkAcceptsTouch](QQuickItem *item,
const QEvent *ev) -> std::optional<
bool> {
2265 const QPointerEvent *event =
static_cast<
const QPointerEvent *>(ev);
2266 auto itemPrivate = QQuickItemPrivate::get(item);
2267 if (itemPrivate->hasPointerHandlers()) {
2268 if (itemPrivate->anyPointerHandlerWants(event, point))
2271 if (checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
2273 if (checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
2277 return std::nullopt;
2280 return eventTargets(item, event, point.id(), item->mapFromScene(point.scenePosition()), point.scenePosition(), predicate);
2284
2285
2286
2287QList<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(
const QList<QQuickItem *> &list1,
const QList<QQuickItem *> &list2)
const
2289 QList<QQuickItem *> targets = list1;
2293 int insertPosition = targets.size();
2294 for (
int i = list2.size() - 1; i >= 0; --i) {
2295 int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
2296 if (newInsertPosition >= 0) {
2297 Q_ASSERT(newInsertPosition <= insertPosition);
2298 insertPosition = newInsertPosition;
2301 if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
2302 targets.insert(insertPosition, list2.at(i));
2308
2309
2310void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
2312 Q_Q(
const QQuickDeliveryAgent);
2314 const auto grabbers = exclusiveGrabbers(event);
2315 hasFiltered.clear();
2316 for (
auto grabber : grabbers) {
2318 QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
2321 QQuickPointerHandler *handler =
static_cast<QQuickPointerHandler *>(grabber);
2322 receiver =
static_cast<QQuickPointerHandler *>(grabber)->parentItem();
2326 hasFiltered.clear();
2327 if (sendFilteredPointerEvent(event, receiver))
2329 localizePointerEvent(event, receiver);
2331 handler->handlePointerEvent(event);
2337 hasFiltered.clear();
2339 deliverMatchingPointsToItem(receiver,
true, event);
2343 for (
auto &point : event->points()) {
2344 auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
2345 if (Q_UNLIKELY(!epd)) {
2346 qWarning() <<
"point is not in activePoints" << point;
2349 QList<QPointer<QObject>> relevantPassiveGrabbers;
2350 for (
int i = 0; i < epd->passiveGrabbersContext.size(); ++i) {
2351 if (epd->passiveGrabbersContext.at(i).data() == q)
2352 relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
2354 if (!relevantPassiveGrabbers.isEmpty())
2355 deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
2358 if (event->type() == QEvent::TouchUpdate) {
2359 for (
const auto &[item, id] : hoverItems) {
2361 bool res = deliverHoverEventToItem(item, item->mapFromScene(point.scenePosition()), point.scenePosition(), point.sceneLastPosition(),
2362 point.globalPosition(), event->modifiers(), event->timestamp(), HoverChange::Set);
2364 Q_ASSERT(!res || hoverItems.value(item));
2374 if (!allPointsGrabbed(event)) {
2375 QList<QQuickItem *> targetItems;
2376 for (
auto &point : event->points()) {
2379 if (point.state() == QEventPoint::Pressed || qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(point)))
2381 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point,
false,
false);
2382 if (targetItems.size()) {
2383 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2385 targetItems = targetItemsForPoint;
2388 for (QQuickItem *item : targetItems) {
2389 if (grabbers.contains(item))
2391 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2392 localizePointerEvent(event, item);
2393 itemPrivate->handlePointerEvent(event,
true);
2394 if (allPointsGrabbed(event))
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event,
bool handlersOnly)
2441 QList<QQuickItem *> targetItems;
2442 const bool isTouch = isTouchEvent(event);
2443 if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) {
2444 if (
auto point =
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) {
2454 if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint)))
2455 cancelTouchMouseSynthesis();
2457 qCWarning(lcTouchTarget) <<
"during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId <<
"is missing from" << event;
2460 for (
int i = 0; i < event->pointCount(); ++i) {
2461 auto &point = event->point(i);
2465 if (isTouch && point.state() == QEventPoint::Pressed)
2466 resetIfDoubleTapPrevented(point);
2467 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch);
2468 if (targetItems.size()) {
2469 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2471 targetItems = targetItemsForPoint;
2475 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
2477 for (
auto &item : safeTargetItems) {
2481 if (isSubsceneAgent)
2482 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
2484 hasFiltered.clear();
2485 if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
2486 if (event->isAccepted())
2488 skipDelivery.append(item);
2493 if (skipDelivery.contains(item))
2498 for (
int i = 0; i < event->pointCount(); ++i)
2499 event->point(i).setAccepted(
false);
2501 deliverMatchingPointsToItem(item,
false, event, handlersOnly);
2502 if (event->allPointsAccepted())
2503 handlersOnly =
true;
2509 return handlersOnly;
2513
2514
2515
2516
2517
2518
2519
2520void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item,
bool isGrabber, QPointerEvent *pointerEvent,
bool handlersOnly)
2522 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2523#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
2528 if (itemPrivate->wasDeleted)
2531 localizePointerEvent(pointerEvent, item);
2532 bool isMouse = isMouseEvent(pointerEvent);
2536 if (pointerEvent->type() != QEvent::MouseButtonDblClick)
2537 itemPrivate->handlePointerEvent(pointerEvent);
2544 if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent()
2545 && !exclusiveGrabbers(pointerEvent).contains(item))
2549 if (sendFilteredPointerEvent(pointerEvent, item))
2555 auto button =
static_cast<QSinglePointEvent *>(pointerEvent)->button();
2556 if ((isGrabber && button == Qt::NoButton) || item->acceptedMouseButtons().testFlag(button)) {
2559 auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0));
2560 pointerEvent->accept();
2561 if (isGrabber && sendFilteredPointerEvent(pointerEvent, item))
2563 localizePointerEvent(pointerEvent, item);
2564 QCoreApplication::sendEvent(item, pointerEvent);
2565 if (pointerEvent->isAccepted()) {
2566 auto &point = pointerEvent->point(0);
2567 auto mouseGrabber = pointerEvent->exclusiveGrabber(point);
2568 if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
2574 if (item != lastUngrabbed) {
2575 item->mouseUngrabEvent();
2576 lastUngrabbed = item;
2578 }
else if (item->isEnabled() && item->isVisible() && point.state() == QEventPoint::State::Pressed) {
2579 pointerEvent->setExclusiveGrabber(point, item);
2581 point.setAccepted(
true);
2587 if (!isTouchEvent(pointerEvent))
2590 bool eventAccepted =
false;
2591 QMutableTouchEvent touchEvent;
2592 itemPrivate->localizedTouchEvent(
static_cast<QTouchEvent *>(pointerEvent),
false, &touchEvent);
2593 if (touchEvent.type() == QEvent::None)
2596 if (item->acceptTouchEvents()) {
2597 qCDebug(lcTouch) <<
"considering delivering" << &touchEvent <<
" to " << item;
2600 qCDebug(lcTouch) <<
"actually delivering" << &touchEvent <<
" to " << item;
2601 QCoreApplication::sendEvent(item, &touchEvent);
2602 eventAccepted = touchEvent.isAccepted();
2605 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2606 !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
2607 deliverTouchAsMouse(item, &touchEvent);
2611 Q_ASSERT(item->acceptTouchEvents());
2612 if (eventAccepted) {
2613 bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
2614 for (
int i = 0; i < touchEvent.pointCount(); ++i) {
2615 auto &point = touchEvent.point(i);
2617 point.setAccepted();
2619 if (isPressOrRelease && !(itemPrivate->deliveryAgent() && pointerEvent->exclusiveGrabber(point)))
2620 pointerEvent->setExclusiveGrabber(point, item);
2625 for (
const auto &point: touchEvent.points()) {
2626 if (point.state() == QEventPoint::State::Pressed) {
2627 if (pointerEvent->exclusiveGrabber(point) == item) {
2628 qCDebug(lcTouchTarget) <<
"TP" << Qt::hex << point.id() <<
"disassociated";
2629 pointerEvent->setExclusiveGrabber(point,
nullptr);
2636#if QT_CONFIG(quick_draganddrop)
2637void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
2639 QObject *formerTarget = grabber->target();
2640 grabber->resetTarget();
2641 QQuickDragGrabber::iterator grabItem = grabber->begin();
2642 if (grabItem != grabber->end()) {
2643 Q_ASSERT(event->type() != QEvent::DragEnter);
2644 if (event->type() == QEvent::Drop) {
2645 QDropEvent *e =
static_cast<QDropEvent *>(event);
2646 for (e->setAccepted(
false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
2647 QPointF p = (**grabItem)->mapFromScene(e->position().toPoint());
2648 QDropEvent translatedEvent(
2650 e->possibleActions(),
2654 QQuickDropEventEx::copyActions(&translatedEvent, *e);
2655 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2656 e->setAccepted(translatedEvent.isAccepted());
2657 e->setDropAction(translatedEvent.dropAction());
2658 grabber->setTarget(**grabItem);
2661 if (event->type() != QEvent::DragMove) {
2662 QDragLeaveEvent leaveEvent;
2663 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2664 QCoreApplication::sendEvent(**grabItem, &leaveEvent);
2665 grabber->ignoreList().clear();
2668 QDragMoveEvent *moveEvent =
static_cast<QDragMoveEvent *>(event);
2672 QVarLengthArray<QQuickItem*, 64> currentGrabItems;
2673 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2674 currentGrabItems.append(**grabItem);
2677 QDragEnterEvent enterEvent(
2678 moveEvent->position().toPoint(),
2679 moveEvent->possibleActions(),
2680 moveEvent->mimeData(),
2681 moveEvent->buttons(),
2682 moveEvent->modifiers());
2683 QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
2684 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, ¤tGrabItems,
2687 for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
2688 int i = currentGrabItems.indexOf(**grabItem);
2690 currentGrabItems.remove(i);
2692 QDragMoveEvent translatedEvent(
2693 (**grabItem)->mapFromScene(moveEvent->position().toPoint()).toPoint(),
2694 moveEvent->possibleActions(),
2695 moveEvent->mimeData(),
2696 moveEvent->buttons(),
2697 moveEvent->modifiers());
2698 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
2699 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2700 event->setAccepted(translatedEvent.isAccepted());
2701 QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
2706 QDragLeaveEvent leaveEvent;
2707 for (QQuickItem *i : currentGrabItems)
2708 QCoreApplication::sendEvent(i, &leaveEvent);
2713 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
2714 QDragMoveEvent *e =
static_cast<QDragMoveEvent *>(event);
2715 QDragEnterEvent enterEvent(
2716 e->position().toPoint(),
2717 e->possibleActions(),
2721 QQuickDropEventEx::copyActions(&enterEvent, *e);
2722 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
2724 grabber->ignoreList().clear();
2728bool QQuickDeliveryAgentPrivate::deliverDragEvent(
2729 QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
2730 QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
2732 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2733 if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
2735 QPointF p = item->mapFromScene(event->position().toPoint());
2736 bool itemContained = item->contains(p);
2738 const int itemIndex = grabber->ignoreList().indexOf(item);
2739 if (!itemContained) {
2741 grabber->ignoreList().remove(itemIndex);
2743 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
2747 QDragEnterEvent enterEvent(
2748 event->position().toPoint(),
2749 event->possibleActions(),
2752 event->modifiers());
2753 QQuickDropEventEx::copyActions(&enterEvent, *event);
2754 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2757 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2758 if (children.at(ii)->z() < 0)
2760 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2764 if (itemContained) {
2767 if (currentGrabItems && currentGrabItems->contains(item)) {
2768 grabber->grab(item);
2769 grabber->setTarget(item);
2773 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
2774 if (event->type() == QEvent::DragEnter) {
2776 QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
2777 if (formerTargetItem && currentGrabItems) {
2778 QDragLeaveEvent leaveEvent;
2779 QCoreApplication::sendEvent(formerTarget, &leaveEvent);
2783 currentGrabItems->removeAll(formerTarget);
2785 }
else if (itemIndex >= 0) {
2790 QDragMoveEvent translatedEvent(p.toPoint(), event->possibleActions(), event->mimeData(),
2791 event->buttons(), event->modifiers(), event->type());
2792 QQuickDropEventEx::copyActions(&translatedEvent, *event);
2793 translatedEvent.setAccepted(event->isAccepted());
2794 QCoreApplication::sendEvent(item, &translatedEvent);
2795 event->setAccepted(translatedEvent.isAccepted());
2796 event->setDropAction(translatedEvent.dropAction());
2797 if (event->type() == QEvent::DragEnter) {
2798 if (translatedEvent.isAccepted()) {
2799 grabber->grab(item);
2800 grabber->setTarget(item);
2802 }
else if (itemIndex < 0) {
2803 grabber->ignoreList().append(item);
2812 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2813 if (children.at(ii)->z() >= 0)
2815 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2824
2825
2826
2827
2828
2829
2830
2831bool QQuickDeliveryAgentPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2833 return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
2837
2838
2839bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2841 if (!allowChildEventFiltering)
2843 if (!filteringParent)
2845 bool filtered =
false;
2846 const bool hasHandlers = QQuickItemPrivate::get(receiver)->hasPointerHandlers();
2847 if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
2848 hasFiltered.append(filteringParent);
2849 if (isMouseEvent(event)) {
2850 if (receiver->acceptedMouseButtons()) {
2851 const bool wasAccepted = event->allPointsAccepted();
2852 Q_ASSERT(event->pointCount());
2853 localizePointerEvent(event, receiver);
2854 event->setAccepted(
true);
2855 auto oldMouseGrabber = event->exclusiveGrabber(event->point(0));
2856 if (filteringParent->childMouseEventFilter(receiver, event)) {
2857 qCDebug(lcMouse) <<
"mouse event intercepted by childMouseEventFilter of " << filteringParent;
2858 skipDelivery.append(filteringParent);
2860 if (event->isAccepted() && event->isBeginEvent()) {
2861 auto &point = event->point(0);
2862 auto mouseGrabber = event->exclusiveGrabber(point);
2863 if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
2864 receiver->mouseUngrabEvent();
2866 event->setExclusiveGrabber(point, receiver);
2871 event->setAccepted(wasAccepted);
2874 }
else if (isTouchEvent(event)) {
2875 const bool acceptsTouchEvents = receiver->acceptTouchEvents() || hasHandlers;
2876 auto device = event->device();
2877 if (device->type() == QInputDevice::DeviceType::TouchPad &&
2878 device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
2879 qCDebug(lcTouchTarget) <<
"skipping filtering of synth-mouse event from" << device;
2880 }
else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
2883 QMutableTouchEvent filteringParentTouchEvent;
2884 QQuickItemPrivate::get(receiver)->localizedTouchEvent(
static_cast<QTouchEvent *>(event),
true, &filteringParentTouchEvent);
2885 if (filteringParentTouchEvent.type() != QEvent::None) {
2886 qCDebug(lcTouch) <<
"letting parent" << filteringParent <<
"filter for" << receiver << &filteringParentTouchEvent;
2887 filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent);
2889 qCDebug(lcTouch) <<
"touch event intercepted by childMouseEventFilter of " << filteringParent;
2890 event->setAccepted(filteringParentTouchEvent.isAccepted());
2891 skipDelivery.append(filteringParent);
2892 if (event->isAccepted()) {
2893 for (
auto point : filteringParentTouchEvent.points()) {
2894 const QQuickItem *exclusiveGrabber = qobject_cast<
const QQuickItem *>(event->exclusiveGrabber(point));
2895 if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab())
2896 event->setExclusiveGrabber(point, filteringParent);
2899 }
else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2900 !filteringParent->acceptTouchEvents()) {
2901 qCDebug(lcTouch) <<
"touch event NOT intercepted by childMouseEventFilter of " << filteringParent
2902 <<
"; accepts touch?" << filteringParent->acceptTouchEvents()
2903 <<
"receiver accepts touch?" << acceptsTouchEvents
2904 <<
"so, letting parent filter a synth-mouse event";
2906 for (
auto &tp : filteringParentTouchEvent.points()) {
2908 switch (tp.state()) {
2909 case QEventPoint::State::Pressed:
2910 t = QEvent::MouseButtonPress;
2912 case QEventPoint::State::Released:
2913 t = QEvent::MouseButtonRelease;
2915 case QEventPoint::State::Stationary:
2918 t = QEvent::MouseMove;
2922 bool touchMouseUnset = (touchMouseId == -1);
2924 if (touchMouseUnset || touchMouseId == tp.id()) {
2927 QMutableSinglePointEvent mouseEvent;
2928 touchToMouseEvent(t, tp, &filteringParentTouchEvent, &mouseEvent);
2932 touchMouseId = tp.id();
2933 touchMouseDevice = event->pointingDevice();
2934 filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent);
2936 qCDebug(lcTouch) <<
"touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
2937 event->setAccepted(mouseEvent.isAccepted());
2938 skipDelivery.append(filteringParent);
2939 if (event->isAccepted() && event->isBeginEvent()) {
2940 qCDebug(lcTouchTarget) <<
"TP (mouse)" << Qt::hex << tp.id() <<
"->" << filteringParent;
2941 filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent);
2942 touchMouseUnset =
false;
2943 filteringParent->grabMouse();
2946 if (touchMouseUnset)
2949 cancelTouchMouseSynthesis();
2950 mouseEvent.point(0).setAccepted(
false);
2961 return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975bool QQuickDeliveryAgentPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2977 if (!filteringParent)
2980 QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
2981 if (filteringParentPrivate->replayingPressEvent)
2984 bool filtered =
false;
2985 if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
2986 hasFiltered.append(filteringParent);
2987 if (filteringParent->childMouseEventFilter(receiver, event)) {
2989 skipDelivery.append(filteringParent);
2991 qCDebug(lcMouseTarget) <<
"for" << receiver << filteringParent <<
"childMouseEventFilter ->" << filtered;
2994 return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
2998
2999
3000
3001
3002
3003
3004bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event,
int startDragThreshold)
3006 QStyleHints *styleHints = QGuiApplication::styleHints();
3007 bool dragVelocityLimitAvailable = event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
3008 && styleHints->startDragVelocity();
3009 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3010 if (dragVelocityLimitAvailable) {
3011 QVector2D velocityVec = event->point(0).velocity();
3012 qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
3013 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3015 return overThreshold;
3019
3020
3021
3022
3023
3024
3025bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const QEventPoint &tp,
int startDragThreshold)
3027 QStyleHints *styleHints = qApp->styleHints();
3028 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3029 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
3030 if (!overThreshold && dragVelocityLimitAvailable) {
3031 qreal velocity = axis == Qt::XAxis ? tp.velocity().x() : tp.velocity().y();
3032 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3034 return overThreshold;
3038
3039
3040
3041
3042bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
3044 int threshold = qApp->styleHints()->startDragDistance();
3045 return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
3049
3050
3051
3052
3053
3054
3055QList<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item,
const QContextMenuEvent *event)
const
3057 auto predicate = [](QQuickItem *,
const QEvent *) -> std::optional<
bool> {
3058 return std::nullopt;
3061 const auto pos = event->pos().isNull() ? activeFocusItem->mapToScene({}).toPoint() : event->pos();
3062 if (event->pos().isNull())
3063 qCDebug(lcContextMenu) <<
"for QContextMenuEvent, active focus item is" << activeFocusItem <<
"@" << pos;
3064 return eventTargets(item, event, -1, pos, pos, predicate);
3068
3069
3070
3071
3072void QQuickDeliveryAgentPrivate::deliverContextMenuEvent(QContextMenuEvent *event)
3074 skipDelivery.clear();
3075 QList<QQuickItem *> targetItems = contextMenuTargets(rootItem, event);
3076 qCDebug(lcContextMenu) <<
"delivering context menu event" << event <<
"to" << targetItems.size() <<
"target item(s)";
3077 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
3078 for (
auto &item : safeTargetItems) {
3079 qCDebug(lcContextMenu) <<
"- attempting to deliver to" << item;
3083 if (isSubsceneAgent)
3084 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
3086 QCoreApplication::sendEvent(item, event);
3087 if (event->isAccepted())
3092#ifndef QT_NO_DEBUG_STREAM
3095 QDebugStateSaver saver(debug);
3098 debug <<
"QQuickDeliveryAgent(0)";
3102 debug <<
"QQuickDeliveryAgent(";
3103 if (!da->objectName().isEmpty())
3104 debug << da->objectName() <<
' ';
3105 auto root = da->rootItem();
3106 if (Q_LIKELY(root)) {
3107 debug <<
"root=" << root->metaObject()->className();
3108 if (!root->objectName().isEmpty())
3109 debug <<
' ' << root->objectName();
3120#include "moc_qquickdeliveryagent_p.cpp"
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static bool allowSyntheticRightClick()
static bool windowHasFocus(QQuickWindow *win)
static QQuickItem * findFurthestFocusScopeAncestor(QQuickItem *item)