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")
43extern 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);
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 return win == focusWindow || QQuickRenderControlPrivate::isRenderWindowFor(win, focusWindow) || !focusWindow;
387 QQuickItem *parentItem = item->parentItem();
389 if (parentItem && parentItem->flags() & QQuickItem::ItemIsFocusScope)
390 return findFurthestFocusScopeAncestor(parentItem);
397static inline bool singleWindowOnScreen(QQuickWindow *win)
399 const QWindowList windowList = QGuiApplication::allWindows();
400 for (
int i = 0; i < windowList.count(); i++) {
401 QWindow *ii = windowList.at(i);
404 if (ii->screen() == win->screen())
413
414
415
416
417void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *item,
418 Qt::FocusReason reason, FocusOptions options)
420 Q_Q(QQuickDeliveryAgent);
422 Q_ASSERT(scope || item == rootItem);
424 qCDebug(lcFocus) << q <<
"focus" << item <<
"in scope" << scope;
426 qCDebug(lcFocus) <<
" scopeSubFocusItem:" << QQuickItemPrivate::get(scope)->subFocusItem;
428 QQuickItemPrivate *scopePrivate = scope ? QQuickItemPrivate::get(scope) :
nullptr;
429 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
431 QQuickItem *oldActiveFocusItem =
nullptr;
432 QQuickItem *currentActiveFocusItem = activeFocusItem;
433 QQuickItem *newActiveFocusItem =
nullptr;
434 bool sendFocusIn =
false;
436 lastFocusReason = reason;
438 QVarLengthArray<QQuickItem *, 20> changed;
441 if (item == rootItem || scopePrivate->activeFocus) {
442 oldActiveFocusItem = activeFocusItem;
443 if (item->isEnabled()) {
444 newActiveFocusItem = item;
445 while (newActiveFocusItem->isFocusScope()
446 && newActiveFocusItem->scopedFocusItem()
447 && newActiveFocusItem->scopedFocusItem()->isEnabled()) {
448 newActiveFocusItem = newActiveFocusItem->scopedFocusItem();
451 newActiveFocusItem = scope;
454 if (oldActiveFocusItem) {
456 QGuiApplication::inputMethod()->commit();
459 activeFocusItem =
nullptr;
461 QQuickItem *afi = oldActiveFocusItem;
462 while (afi && afi != scope) {
463 if (QQuickItemPrivate::get(afi)->activeFocus) {
464 QQuickItemPrivate::get(afi)->activeFocus =
false;
467 afi = afi->parentItem();
472 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
473 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
474 if (oldSubFocusItem) {
475 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
477 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
478 changed << oldSubFocusItem;
481 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
true);
484 if (!(options & DontChangeFocusProperty)) {
485 if (item != rootItem || windowHasFocus(rootItem->window())
489 || singleWindowOnScreen(rootItem->window())
492 itemPrivate->focus =
true;
493 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
498 if (newActiveFocusItem && (rootItem->hasFocus() || (rootItem->window()->type() == Qt::Popup))) {
499 activeFocusItem = newActiveFocusItem;
501 QQuickItemPrivate::get(newActiveFocusItem)->activeFocus =
true;
502 changed << newActiveFocusItem;
504 QQuickItem *afi = newActiveFocusItem->parentItem();
505 while (afi && afi != scope) {
506 if (afi->isFocusScope()) {
507 QQuickItemPrivate::get(afi)->activeFocus =
true;
510 afi = afi->parentItem();
512 updateFocusItemTransform();
518 if (oldActiveFocusItem) {
519 QFocusEvent event(QEvent::FocusOut, reason);
520 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
524 if (sendFocusIn && activeFocusItem == newActiveFocusItem) {
525 QFocusEvent event(QEvent::FocusIn, reason);
526 QCoreApplication::sendEvent(newActiveFocusItem, &event);
529 if (activeFocusItem != currentActiveFocusItem)
530 emit rootItem->window()->focusObjectChanged(activeFocusItem);
532 if (!changed.isEmpty())
533 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
534 if (isSubsceneAgent) {
535 auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent;
536 qCDebug(lcFocus) <<
" delegating setFocusInScope to" << da;
544 QQuickItem *ancestorFS = findFurthestFocusScopeAncestor(item);
545 if (ancestorFS != item)
546 options |= QQuickDeliveryAgentPrivate::DontChangeSubFocusItem;
547 QQuickWindowPrivate::get(rootItem->window())->deliveryAgentPrivate()->setFocusInScope(da->rootItem(), item, reason, options);
549 if (oldActiveFocusItem == activeFocusItem)
550 qCDebug(lcFocus) <<
" activeFocusItem remains" << activeFocusItem <<
"in" << q;
552 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
555void QQuickDeliveryAgentPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions options)
558 Q_ASSERT(scope || item == rootItem);
559 Q_Q(QQuickDeliveryAgent);
560 qCDebug(lcFocus) << q <<
"clear focus" << item <<
"in scope" << scope;
562 QQuickItemPrivate *scopePrivate =
nullptr;
564 scopePrivate = QQuickItemPrivate::get(scope);
565 if ( !scopePrivate->subFocusItem )
569 QQuickItem *currentActiveFocusItem = activeFocusItem;
570 QQuickItem *oldActiveFocusItem =
nullptr;
571 QQuickItem *newActiveFocusItem =
nullptr;
573 lastFocusReason = reason;
575 QVarLengthArray<QQuickItem *, 20> changed;
577 Q_ASSERT(item == rootItem || item == scopePrivate->subFocusItem);
580 if (item == rootItem || scopePrivate->activeFocus) {
581 oldActiveFocusItem = activeFocusItem;
582 newActiveFocusItem = scope;
585 QGuiApplication::inputMethod()->commit();
588 activeFocusItem =
nullptr;
590 if (oldActiveFocusItem) {
591 QQuickItem *afi = oldActiveFocusItem;
592 while (afi && afi != scope) {
593 if (QQuickItemPrivate::get(afi)->activeFocus) {
594 QQuickItemPrivate::get(afi)->activeFocus =
false;
597 afi = afi->parentItem();
602 if (item != rootItem && !(options & DontChangeSubFocusItem)) {
603 QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
604 if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
605 QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
607 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
608 changed << oldSubFocusItem;
611 QQuickItemPrivate::get(item)->updateSubFocusItem(scope,
false);
613 }
else if (!(options & DontChangeFocusProperty)) {
614 QQuickItemPrivate *priv = QQuickItemPrivate::get(item);
616 priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
620 if (newActiveFocusItem) {
621 Q_ASSERT(newActiveFocusItem == scope);
622 activeFocusItem = scope;
623 updateFocusItemTransform();
628 if (oldActiveFocusItem) {
629 QFocusEvent event(QEvent::FocusOut, reason);
630 QCoreApplication::sendEvent(oldActiveFocusItem, &event);
634 if (newActiveFocusItem && activeFocusItem == newActiveFocusItem) {
635 QFocusEvent event(QEvent::FocusIn, reason);
636 QCoreApplication::sendEvent(newActiveFocusItem, &event);
639 QQuickWindow *rootItemWindow = rootItem->window();
640 if (activeFocusItem != currentActiveFocusItem && rootItemWindow)
641 emit rootItemWindow->focusObjectChanged(activeFocusItem);
643 if (!changed.isEmpty())
644 notifyFocusChangesRecur(changed.data(), changed.size() - 1, reason);
645 if (isSubsceneAgent && rootItemWindow) {
646 auto da = QQuickWindowPrivate::get(rootItemWindow)->deliveryAgent;
647 qCDebug(lcFocus) <<
" delegating clearFocusInScope to" << da;
648 QQuickWindowPrivate::get(rootItemWindow)->deliveryAgentPrivate()->clearFocusInScope(da->rootItem(), item, reason, options);
650 if (oldActiveFocusItem == activeFocusItem)
651 qCDebug(lcFocus) <<
"activeFocusItem remains" << activeFocusItem <<
"in" << q;
653 qCDebug(lcFocus) <<
" activeFocusItem" << oldActiveFocusItem <<
"->" << activeFocusItem <<
"in" << q;
656void QQuickDeliveryAgentPrivate::clearFocusObject()
658 if (activeFocusItem == rootItem)
661 clearFocusInScope(rootItem, QQuickItemPrivate::get(rootItem)->subFocusItem, Qt::OtherFocusReason);
664void QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(QQuickItem **items,
int remaining, Qt::FocusReason reason)
666 QPointer<QQuickItem> item(*items);
669 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
671 if (itemPrivate->notifiedFocus != itemPrivate->focus) {
672 itemPrivate->notifiedFocus = itemPrivate->focus;
673 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
674 emit item->focusChanged(itemPrivate->focus);
677 if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
678 itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
679 itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged,
bool(itemPrivate->activeFocus));
680 itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
681 emit item->activeFocusChanged(itemPrivate->activeFocus);
686 notifyFocusChangesRecur(items + 1, remaining - 1, reason);
689bool QQuickDeliveryAgentPrivate::clearHover(ulong timestamp)
691 if (hoverItems.isEmpty())
694 QQuickWindow *window = rootItem->window();
698 const auto globalPos = QGuiApplicationPrivate::lastCursorPosition;
699 const QPointF lastPos = window->mapFromGlobal(globalPos);
700 const auto modifiers = QGuiApplication::keyboardModifiers();
708 for (
auto it = hoverItems.cbegin(); it != hoverItems.cend(); ++it) {
709 if (QQuickItem *item = it->item) {
710 deliverHoverEventToItem(item, item->mapFromScene(lastPos), lastPos, lastPos,
711 globalPos, modifiers, timestamp, HoverChange::Clear);
712 Q_ASSERT(([
this, item]{
713 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
714 return it2 == hoverItems.cend() || it2->hoverId == 0;
722void QQuickDeliveryAgentPrivate::updateFocusItemTransform()
725 if (activeFocusItem && QGuiApplication::focusObject() == activeFocusItem) {
726 QQuickItemPrivate *focusPrivate = QQuickItemPrivate::get(activeFocusItem);
727 QGuiApplication::inputMethod()->setInputItemTransform(focusPrivate->itemToWindowTransform());
728 QGuiApplication::inputMethod()->setInputItemRectangle(QRectF(0, 0, focusPrivate->width, focusPrivate->height));
729 activeFocusItem->updateInputMethod(Qt::ImInputItemClipRectangle);
735
736
737
738QQuickItem *QQuickDeliveryAgentPrivate::focusTargetItem()
const
741 return activeFocusItem;
744 QQuickItem *targetItem = rootItem;
746 while (targetItem->isFocusScope()
747 && targetItem->scopedFocusItem()
748 && targetItem->scopedFocusItem()->isEnabled()) {
749 targetItem = targetItem->scopedFocusItem();
756
757
758
759
760
761QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(
const QQuickItem *item)
763 if (currentEventDeliveryAgent)
764 return currentEventDeliveryAgent;
766 return QQuickItemPrivate::get(
const_cast<QQuickItem *>(item))->deliveryAgent();
771
772
773
774
775QQuickDeliveryAgent::QQuickDeliveryAgent(QQuickItem *rootItem)
776 : QObject(*
new QQuickDeliveryAgentPrivate(rootItem), rootItem)
780QQuickDeliveryAgent::~QQuickDeliveryAgent()
784QQuickDeliveryAgent::Transform::~Transform()
789
790
791
792QQuickItem *QQuickDeliveryAgent::rootItem()
const
794 Q_D(
const QQuickDeliveryAgent);
799
800
801
802
803QQuickDeliveryAgent::Transform *QQuickDeliveryAgent::sceneTransform()
const
805 Q_D(
const QQuickDeliveryAgent);
806 return d->sceneTransform;
810
811
812
813
814void QQuickDeliveryAgent::setSceneTransform(QQuickDeliveryAgent::Transform *transform)
816 Q_D(QQuickDeliveryAgent);
817 if (d->sceneTransform == transform)
819 qCDebug(lcPtr) <<
this << d->sceneTransform <<
"->" << transform;
820 if (d->sceneTransform)
821 delete d->sceneTransform;
822 d->sceneTransform = transform;
826
827
828
829
830
831
832bool QQuickDeliveryAgent::event(QEvent *ev)
834 Q_D(QQuickDeliveryAgent);
835 d->currentEventDeliveryAgent =
this;
836 auto cleanup = qScopeGuard([d] { d->currentEventDeliveryAgent =
nullptr; });
838 switch (ev->type()) {
839 case QEvent::MouseButtonPress:
840 case QEvent::MouseButtonRelease:
841 case QEvent::MouseButtonDblClick:
842 case QEvent::MouseMove: {
843 QMouseEvent *me =
static_cast<QMouseEvent*>(ev);
844 d->handleMouseEvent(me);
847 case QEvent::HoverEnter:
848 case QEvent::HoverLeave:
849 case QEvent::HoverMove: {
850 QHoverEvent *he =
static_cast<QHoverEvent*>(ev);
851 bool accepted = d->deliverHoverEvent(he->scenePosition(),
852 he->points().first().sceneLastPosition(),
853 he->modifiers(), he->timestamp());
854 d->lastMousePosition = he->scenePosition();
855 he->setAccepted(accepted);
857 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(d->sceneTransform ?
858 d->sceneTransform->map(he->scenePosition()) : he->scenePosition(), d->rootItem);
862 case QEvent::TouchBegin:
863 case QEvent::TouchUpdate:
864 case QEvent::TouchEnd: {
865 QTouchEvent *touch =
static_cast<QTouchEvent*>(ev);
866 d->handleTouchEvent(touch);
867 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
874 case QEvent::TouchCancel:
876 return d->deliverTouchCancelEvent(
static_cast<QTouchEvent*>(ev));
878 case QEvent::Enter: {
881 QEnterEvent *enter =
static_cast<QEnterEvent*>(ev);
882 const auto scenePos = enter->scenePosition();
883 qCDebug(lcHoverTrace) <<
this <<
"sending hover event due to QEnterEvent" << enter;
884 bool accepted = d->deliverHoverEvent(scenePos,
885 enter->points().first().sceneLastPosition(),
886 enter->modifiers(), enter->timestamp());
887 d->lastMousePosition = scenePos;
889 Q_ASSERT(enter->scenePosition() == scenePos);
890 enter->setAccepted(accepted);
892 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(enter->scenePosition(), d->rootItem);
898 d->lastMousePosition = QPointF();
900#if QT_CONFIG(quick_draganddrop)
901 case QEvent::DragEnter:
902 case QEvent::DragLeave:
903 case QEvent::DragMove:
905 d->deliverDragEvent(d->dragGrabber, ev);
908 case QEvent::FocusAboutToChange:
910 if (d->activeFocusItem)
911 qGuiApp->inputMethod()->commit();
914#if QT_CONFIG(gestures)
915 case QEvent::NativeGesture:
916 d->deliverSinglePointEventUntilAccepted(
static_cast<QPointerEvent *>(ev));
919 case QEvent::ShortcutOverride:
920 d->deliverKeyEvent(
static_cast<QKeyEvent *>(ev));
922 case QEvent::InputMethod:
923 case QEvent::InputMethodQuery:
925 QQuickItem *target = d->focusTargetItem();
927 QCoreApplication::sendEvent(target, ev);
930#if QT_CONFIG(wheelevent)
931 case QEvent::Wheel: {
932 auto event =
static_cast<QWheelEvent *>(ev);
933 qCDebug(lcMouse) << event;
936 if (d->lastWheelEventAccepted && event->angleDelta().isNull() && event->phase() == Qt::ScrollUpdate)
940 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseWheel,
941 event->angleDelta().x(), event->angleDelta().y());
942 d->deliverSinglePointEventUntilAccepted(event);
943 d->lastWheelEventAccepted = event->isAccepted();
947#if QT_CONFIG(tabletevent)
948 case QEvent::TabletPress:
949 case QEvent::TabletMove:
950 case QEvent::TabletRelease:
952 auto *tabletEvent =
static_cast<QTabletEvent *>(ev);
953 d->deliverPointerEvent(tabletEvent);
955 QQuickWindowPrivate::get(d->rootItem->window())->updateCursor(tabletEvent->scenePosition(), d->rootItem);
960#ifndef QT_NO_CONTEXTMENU
961 case QEvent::ContextMenu:
962 d->deliverContextMenuEvent(
static_cast<QContextMenuEvent *>(ev));
966 Q_ASSERT(
static_cast<QTimerEvent *>(ev)->timerId() == d->frameSynchronousDelayTimer.timerId());
967 d->frameSynchronousDelayTimer.stop();
968 d->flushFrameSynchronousEvents(d->rootItem->window());
977void QQuickDeliveryAgentPrivate::deliverKeyEvent(QKeyEvent *e)
979 if (activeFocusItem) {
980 const bool keyPress = (e->type() == QEvent::KeyPress);
982 case QEvent::KeyPress:
983 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyPress, e->key(), e->modifiers());
985 case QEvent::KeyRelease:
986 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Key, QQuickProfiler::InputKeyRelease, e->key(), e->modifiers());
992 QQuickItem *item = activeFocusItem;
995 if (keyPress && e->spontaneous() ==
false)
996 qt_sendShortcutOverrideEvent(item, e->timestamp(),
997 e->key(), e->modifiers(), e->text(),
998 e->isAutoRepeat(), e->count());
1001 Q_ASSERT(e->type() != QEvent::ShortcutOverride || !e->isAccepted());
1002 if (e->type() != QEvent::ShortcutOverride)
1004 QCoreApplication::sendEvent(item, e);
1005 }
while (!e->isAccepted() && (item = item->parentItem()));
1009QQuickDeliveryAgentPrivate::QQuickDeliveryAgentPrivate(QQuickItem *root) :
1013 isSubsceneAgent(!qmlobject_cast<QQuickRootItem *>(rootItem))
1015#if QT_CONFIG(quick_draganddrop)
1016 dragGrabber =
new QQuickDragGrabber;
1018 if (isSubsceneAgent)
1019 subsceneAgentsExist =
true;
1020 const auto interval = qEnvironmentVariableIntegerValue(
"QT_QUICK_FRAME_SYNCHRONOUS_HOVER_INTERVAL");
1021 if (interval.has_value()) {
1022 qCDebug(lcHoverTrace) <<
"frame-synchronous hover interval" << interval;
1023 frameSynchronousHoverInterval =
int(interval.value());
1025 if (frameSynchronousHoverInterval > 0)
1026 frameSynchronousHoverTimer.start();
1029QQuickDeliveryAgentPrivate::~QQuickDeliveryAgentPrivate()
1031#if QT_CONFIG(quick_draganddrop)
1033 dragGrabber =
nullptr;
1035 delete sceneTransform;
1039
1040
1041
1042
1043
1044
1045QPointerEvent *QQuickDeliveryAgentPrivate::clonePointerEvent(QPointerEvent *event, std::optional<QPointF> transformedLocalPos)
1047 QPointerEvent *ret = event->clone();
1048 QEventPoint &point = ret->point(0);
1049 QMutableEventPoint::detach(point);
1050 QMutableEventPoint::setTimestamp(point, event->timestamp());
1051 if (transformedLocalPos)
1052 QMutableEventPoint::setPosition(point, *transformedLocalPos);
1057void QQuickDeliveryAgentPrivate::deliverToPassiveGrabbers(
const QList<QPointer <QObject> > &passiveGrabbers,
1058 QPointerEvent *pointerEvent)
1060 const QList<QObject *> &eventDeliveryTargets =
1061 QQuickPointerHandlerPrivate::deviceDeliveryTargets(pointerEvent->device());
1062 QVarLengthArray<std::pair<QQuickItem *,
bool>, 4> sendFilteredPointerEventResult;
1063 hasFiltered.clear();
1064 for (QObject *grabberObject : passiveGrabbers) {
1066 if (Q_UNLIKELY(!grabberObject))
1069 if (QQuickPointerHandler *handler = qobject_cast<QQuickPointerHandler *>(grabberObject)) {
1070 if (handler && !eventDeliveryTargets.contains(handler)) {
1071 bool alreadyFiltered =
false;
1072 QQuickItem *par = handler->parentItem();
1075 auto it = std::find_if(sendFilteredPointerEventResult.begin(), sendFilteredPointerEventResult.end(),
1076 [par](
const std::pair<QQuickItem *,
bool> &pair) {
return pair.first == par; });
1077 if (it != sendFilteredPointerEventResult.end()) {
1080 alreadyFiltered = it->second;
1082 alreadyFiltered = sendFilteredPointerEvent(pointerEvent, par);
1083 sendFilteredPointerEventResult << std::make_pair(par, alreadyFiltered);
1085 if (!alreadyFiltered) {
1087 localizePointerEvent(pointerEvent, par);
1088 handler->handlePointerEvent(pointerEvent);
1091 }
else if (QQuickItem *grabberItem =
static_cast<QQuickItem *>(grabberObject)) {
1093 if (QQuickItem *excGrabber =
static_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(pointerEvent->point(0)))) {
1094 if ((isMouseEvent(pointerEvent) && excGrabber->keepMouseGrab())
1095 || (isTouchEvent(pointerEvent) && excGrabber->keepTouchGrab())) {
1099 localizePointerEvent(pointerEvent, grabberItem);
1100 QCoreApplication::sendEvent(grabberItem, pointerEvent);
1101 pointerEvent->accept();
1106bool QQuickDeliveryAgentPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
1107 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1108 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp)
1110 QHoverEvent hoverEvent(type, scenePos, globalPos, lastScenePos, modifiers);
1111 hoverEvent.setTimestamp(timestamp);
1112 hoverEvent.setAccepted(
true);
1113 QEventPoint &point = hoverEvent.point(0);
1114 QMutableEventPoint::setPosition(point, localPos);
1115 if (Q_LIKELY(item->window()))
1116 QMutableEventPoint::setGlobalLastPosition(point, item->window()->mapToGlobal(lastScenePos));
1118 hasFiltered.clear();
1119 if (sendFilteredMouseEvent(&hoverEvent, item, item->parentItem()))
1122 QCoreApplication::sendEvent(item, &hoverEvent);
1124 return hoverEvent.isAccepted();
1128
1129
1130
1131
1133bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
1134 const QPointF &scenePos,
const QPointF &lastScenePos,
1135 Qt::KeyboardModifiers modifiers, ulong timestamp)
1153 const bool subtreeHoverEnabled = QQuickItemPrivate::get(rootItem)->subtreeHoverEnabled;
1154 const bool itemsWasHovered = !hoverItems.isEmpty();
1156 if (!subtreeHoverEnabled && !itemsWasHovered)
1161 if (subtreeHoverEnabled) {
1162 hoveredLeafItemFound =
false;
1163 QQuickPointerHandlerPrivate::deviceDeliveryTargets(QPointingDevice::primaryPointingDevice()).clear();
1164 deliverHoverEventRecursive(rootItem, scenePos, scenePos, lastScenePos,
1165 rootItem->mapToGlobal(scenePos), modifiers, timestamp);
1169 for (
auto it = hoverItems.begin(); it != hoverItems.end();) {
1170 const auto &[item, hoverId] = *it;
1171 if (hoverId == currentHoverId) {
1178 if (item && hoverId != 0)
1179 deliverHoverEventToItem(item, item->mapFromScene(scenePos), scenePos, lastScenePos,
1180 QGuiApplicationPrivate::lastCursorPosition, modifiers, timestamp, HoverChange::Clear);
1181 it = hoverItems.erase(it);
1185 const bool itemsAreHovered = !hoverItems.isEmpty();
1186 return itemsWasHovered || itemsAreHovered;
1190
1191
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
1225bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(QQuickItem *item,
1226 const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
const QPointF &globalPos,
1227 Qt::KeyboardModifiers modifiers, ulong timestamp)
1229 const QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1230 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
1231 const bool hadChildrenChanged = itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged;
1233 for (
int ii = children.size() - 1; ii >= 0; --ii) {
1237 if (!hadChildrenChanged && Q_UNLIKELY(itemPrivate->dirtyAttributes & QQuickItemPrivate::ChildrenChanged))
1239 QQuickItem *child = children.at(ii);
1240 const QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
1242 if (!child->isVisible() || childPrivate->culled)
1244 if (!childPrivate->subtreeHoverEnabled)
1247 QTransform childToParent;
1248 childPrivate->itemToParentTransform(&childToParent);
1249 const QPointF childLocalPos = childToParent.inverted().map(localPos);
1254 if (childPrivate->effectivelyClipsEventHandlingChildren() &&
1255 !childPrivate->eventHandlingBounds().contains(childLocalPos)) {
1256#ifdef QT_BUILD_INTERNAL
1257 ++QQuickItemPrivate::effectiveClippingSkips_counter;
1263 const bool accepted = deliverHoverEventRecursive(child, childLocalPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1268 if (hoveredLeafItemFound) {
1276 return deliverHoverEventToItem(item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp, HoverChange::Set);
1280
1281
1282
1283
1284
1285
1286
1287bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
1288 QQuickItem *item,
const QPointF &localPos,
const QPointF &scenePos,
const QPointF &lastScenePos,
1289 const QPointF &globalPos, Qt::KeyboardModifiers modifiers, ulong timestamp, HoverChange hoverChange)
1291 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1292 const bool isHovering = item->contains(localPos);
1293 auto hoverItemIterator = findHoverStateByItem(hoverItems, item);
1294 const bool wasHovering = hoverItemIterator != hoverItems.end() && hoverItemIterator->hoverId != 0;
1296 qCDebug(lcHoverTrace) <<
"item:" << item <<
"scene pos:" << scenePos <<
"localPos:" << localPos
1297 <<
"wasHovering:" << wasHovering <<
"isHovering:" << isHovering;
1299 bool accepted =
false;
1304 if (itemPrivate->hoverEnabled && isHovering && hoverChange == HoverChange::Set) {
1309 hoveredLeafItemFound =
true;
1310 if (hoverItemIterator != hoverItems.end())
1311 hoverItemIterator->hoverId = currentHoverId;
1313 hoverItems.append({item, currentHoverId});
1316 accepted = sendHoverEvent(QEvent::HoverMove, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1318 accepted = sendHoverEvent(QEvent::HoverEnter, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1319 }
else if (wasHovering) {
1321 hoverItemIterator->hoverId = 0;
1322 sendHoverEvent(QEvent::HoverLeave, item, localPos, scenePos, lastScenePos, globalPos, modifiers, timestamp);
1325 if (!itemPrivate->hasPointerHandlers())
1335 if (hoverChange == HoverChange::Clear) {
1337 QHoverEvent hoverEvent(QEvent::HoverLeave, scenePos, globalPos, lastScenePos, modifiers);
1338 hoverEvent.setTimestamp(timestamp);
1340 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1341 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1342 if (!hh->isHovered())
1344 hoverEvent.setAccepted(
true);
1345 QCoreApplication::sendEvent(hh, &hoverEvent);
1349 QMouseEvent hoverEvent(QEvent::MouseMove, localPos, scenePos, globalPos, Qt::NoButton, Qt::NoButton, modifiers);
1350 hoverEvent.setTimestamp(timestamp);
1352 for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
1353 if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
1356 hoverEvent.setAccepted(
true);
1357 hh->handlePointerEvent(&hoverEvent);
1358 if (hh->isHovered()) {
1361 hoveredLeafItemFound =
true;
1362 hoverItemIterator = findHoverStateByItem(hoverItems, item);
1363 if (hoverItemIterator != hoverItems.end())
1364 hoverItemIterator->hoverId = currentHoverId;
1366 hoverItems.append({item, currentHoverId});
1367 if (hh->isBlocking()) {
1368 qCDebug(lcHoverTrace) <<
"skipping rest of hover delivery due to blocking" << hh;
1382bool QQuickDeliveryAgentPrivate::deliverSinglePointEventUntilAccepted(QPointerEvent *event)
1384 Q_ASSERT(event->points().size() == 1);
1385 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
1386 QEventPoint &point = event->point(0);
1387 QList<QQuickItem *> targetItems = pointerTargets(rootItem, event, point,
false,
false);
1388 point.setAccepted(
false);
1393 for (
const auto &passiveGrabber : event->passiveGrabbers(point)) {
1394 if (
auto *grabberItem = qobject_cast<QQuickItem *>(passiveGrabber)) {
1395 if (targetItems.contains(grabberItem))
1397 localizePointerEvent(event, grabberItem);
1398 QCoreApplication::sendEvent(grabberItem, event);
1405 for (QQuickItem *item : targetItems) {
1406 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
1407 localizePointerEvent(event, item);
1409 itemPrivate->handlePointerEvent(event);
1410 if (point.isAccepted())
1413 QCoreApplication::sendEvent(item, event);
1414 if (event->isAccepted()) {
1415 qCDebug(lcWheelTarget) << event <<
"->" << item;
1423bool QQuickDeliveryAgentPrivate::deliverTouchCancelEvent(QTouchEvent *event)
1425 qCDebug(lcTouch) << event;
1430 const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(event->pointingDevice()))->
1431 sendTouchCancelEvent(event);
1433 cancelTouchMouseSynthesis();
1438void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent()
1443 std::unique_ptr<QTouchEvent> e(std::move(delayedTouch));
1444 qCDebug(lcTouchCmprs) <<
"delivering" << e.get();
1445 compressedTouchCount = 0;
1446 deliverPointerEvent(e.get());
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459void QQuickDeliveryAgentPrivate::handleWindowDeactivate(QQuickWindow *win)
1461 Q_Q(QQuickDeliveryAgent);
1462 qCDebug(lcFocus) <<
"deactivated" << win->title();
1463 const auto inputDevices = QInputDevice::devices();
1464 for (
auto device : inputDevices) {
1465 if (
auto pointingDevice = qobject_cast<
const QPointingDevice *>(device)) {
1466 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(pointingDevice));
1467 for (
auto epd : devPriv->activePoints.values()) {
1468 if (!epd.exclusiveGrabber.isNull()) {
1469 bool relevant =
false;
1470 if (QQuickItem *item = qmlobject_cast<QQuickItem *>(epd.exclusiveGrabber.data()))
1471 relevant = (item->window() == win);
1472 else if (QQuickPointerHandler *handler = qmlobject_cast<QQuickPointerHandler *>(epd.exclusiveGrabber.data())) {
1473 if (handler->parentItem())
1474 relevant = (handler->parentItem()->window() == win && epd.exclusiveGrabberContext.data() == q);
1481 devPriv->setExclusiveGrabber(
nullptr, epd.eventPoint,
nullptr);
1490void QQuickDeliveryAgentPrivate::handleWindowHidden(QQuickWindow *win)
1492 qCDebug(lcFocus) <<
"hidden" << win->title();
1494 lastMousePosition = QPointF();
1497bool QQuickDeliveryAgentPrivate::allUpdatedPointsAccepted(
const QPointerEvent *ev)
1499 for (
auto &point : ev->points()) {
1500 if (point.state() != QEventPoint::State::Pressed && !point.isAccepted())
1507
1508
1509
1510
1511
1512void QQuickDeliveryAgentPrivate::localizePointerEvent(QPointerEvent *ev,
const QQuickItem *dest)
1514 for (
int i = 0; i < ev->pointCount(); ++i) {
1515 auto &point = ev->point(i);
1516 QMutableEventPoint::setPosition(point, dest->mapFromScene(point.scenePosition()));
1517 qCDebug(lcPtrLoc) << ev->type() <<
"@" << point.scenePosition() <<
"to"
1518 << dest <<
"@" << dest->mapToScene(QPointF()) <<
"->" << point;
1522QList<QObject *> QQuickDeliveryAgentPrivate::exclusiveGrabbers(QPointerEvent *ev)
1524 QList<QObject *> result;
1525 for (
const QEventPoint &point : ev->points()) {
1526 if (QObject *grabber = ev->exclusiveGrabber(point)) {
1527 if (!result.contains(grabber))
1534bool QQuickDeliveryAgentPrivate::anyPointGrabbed(
const QPointerEvent *ev)
1536 for (
const QEventPoint &point : ev->points()) {
1537 if (ev->exclusiveGrabber(point) || !ev->passiveGrabbers(point).isEmpty())
1543bool QQuickDeliveryAgentPrivate::allPointsGrabbed(
const QPointerEvent *ev)
1545 for (
const auto &point : ev->points()) {
1546 if (!ev->exclusiveGrabber(point) && ev->passiveGrabbers(point).isEmpty())
1552bool QQuickDeliveryAgentPrivate::isMouseEvent(
const QPointerEvent *ev)
1554 switch (ev->type()) {
1555 case QEvent::MouseButtonPress:
1556 case QEvent::MouseButtonRelease:
1557 case QEvent::MouseButtonDblClick:
1558 case QEvent::MouseMove:
1565bool QQuickDeliveryAgentPrivate::isMouseOrWheelEvent(
const QPointerEvent *ev)
1567 return isMouseEvent(ev) || ev->type() == QEvent::Wheel;
1570bool QQuickDeliveryAgentPrivate::isHoverEvent(
const QPointerEvent *ev)
1572 switch (ev->type()) {
1573 case QEvent::HoverEnter:
1574 case QEvent::HoverMove:
1575 case QEvent::HoverLeave:
1582bool QQuickDeliveryAgentPrivate::isTouchEvent(
const QPointerEvent *ev)
1584 switch (ev->type()) {
1585 case QEvent::TouchBegin:
1586 case QEvent::TouchUpdate:
1587 case QEvent::TouchEnd:
1588 case QEvent::TouchCancel:
1595bool QQuickDeliveryAgentPrivate::isTabletEvent(
const QPointerEvent *ev)
1597#if QT_CONFIG(tabletevent)
1598 switch (ev->type()) {
1599 case QEvent::TabletPress:
1600 case QEvent::TabletMove:
1601 case QEvent::TabletRelease:
1602 case QEvent::TabletEnterProximity:
1603 case QEvent::TabletLeaveProximity:
1614bool QQuickDeliveryAgentPrivate::isEventFromMouseOrTouchpad(
const QPointerEvent *ev)
1616 const auto devType = ev->device()->type();
1617 return devType == QInputDevice::DeviceType::Mouse ||
1618 devType == QInputDevice::DeviceType::TouchPad;
1621bool QQuickDeliveryAgentPrivate::isSynthMouse(
const QPointerEvent *ev)
1623 return (!isEventFromMouseOrTouchpad(ev) && isMouseEvent(ev));
1627
1628
1629
1630bool QQuickDeliveryAgentPrivate::isSinglePointDevice(
const QInputDevice *dev)
1632 switch (dev->type()) {
1633 case QInputDevice::DeviceType::Mouse:
1634 case QInputDevice::DeviceType::TouchPad:
1635 case QInputDevice::DeviceType::Puck:
1636 case QInputDevice::DeviceType::Stylus:
1637 case QInputDevice::DeviceType::Airbrush:
1639 case QInputDevice::DeviceType::TouchScreen:
1640 case QInputDevice::DeviceType::Keyboard:
1641 case QInputDevice::DeviceType::Unknown:
1642 case QInputDevice::DeviceType::AllDevices:
1648QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(
const QInputDevice *device)
1650 QInputDevicePrivate *devPriv = QInputDevicePrivate::get(
const_cast<QInputDevice *>(device));
1651 if (devPriv->qqExtra)
1652 return static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1653 auto extra =
new QQuickPointingDeviceExtra;
1654 devPriv->qqExtra = extra;
1655 QObject::connect(device, &QObject::destroyed, [devPriv]() {
1656 delete static_cast<QQuickPointingDeviceExtra *>(devPriv->qqExtra);
1657 devPriv->qqExtra =
nullptr;
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
1690 if (isSubsceneAgent)
1693 QEventPoint::States states = event->touchPointStates();
1694 if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
1695 qCDebug(lcTouchCmprs) <<
"no compression" << event;
1700 if (!delayedTouch) {
1701 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points()));
1702 delayedTouch->setTimestamp(event->timestamp());
1703 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1704 auto &tp = delayedTouch->point(i);
1705 QMutableEventPoint::detach(tp);
1707 ++compressedTouchCount;
1708 qCDebug(lcTouchCmprs) <<
"delayed" << compressedTouchCount << delayedTouch.get();
1709 if (QQuickWindow *window = rootItem->window())
1710 window->maybeUpdate();
1715 if (delayedTouch->type() == event->type() &&
1716 delayedTouch->device() == event->device() &&
1717 delayedTouch->modifiers() == event->modifiers() &&
1718 delayedTouch->pointCount() == event->pointCount())
1721 bool mismatch =
false;
1723 auto tpts = event->points();
1724 for (qsizetype i = 0; i < event->pointCount(); ++i) {
1725 const auto &tp = tpts.at(i);
1726 const auto &tpDelayed = delayedTouch->point(i);
1727 if (tp.id() != tpDelayed.id()) {
1732 if (tpDelayed.state() == QEventPoint::State::Updated && tp.state() == QEventPoint::State::Stationary)
1733 QMutableEventPoint::setState(tpts[i], QEventPoint::State::Updated);
1740 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts));
1741 delayedTouch->setTimestamp(event->timestamp());
1742 for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
1743 auto &tp = delayedTouch->point(i);
1744 QMutableEventPoint::detach(tp);
1746 ++compressedTouchCount;
1747 qCDebug(lcTouchCmprs) <<
"coalesced" << compressedTouchCount << delayedTouch.get();
1748 if (QQuickWindow *window = rootItem->window())
1749 window->maybeUpdate();
1755 deliverDelayedTouchEvent();
1756 delayedTouch.reset(
new QMutableTouchEvent(event->type(), event->pointingDevice(),
1757 event->modifiers(), event->points()));
1758 delayedTouch->setTimestamp(event->timestamp());
1766void QQuickDeliveryAgentPrivate::handleTouchEvent(QTouchEvent *event)
1768 Q_Q(QQuickDeliveryAgent);
1769 translateTouchEvent(event);
1771 if (event->pointCount()) {
1772 auto &point = event->point(0);
1773 if (point.state() == QEventPoint::State::Released) {
1774 lastMousePosition = QPointF();
1776 lastMousePosition = point.position();
1780 qCDebug(lcTouch) << q << event;
1782 static bool qquickwindow_no_touch_compression = qEnvironmentVariableIsSet(
"QML_NO_TOUCH_COMPRESSION");
1784 if (qquickwindow_no_touch_compression || pointerEventRecursionGuard) {
1785 deliverPointerEvent(event);
1789 if (!compressTouchEvent(event)) {
1791 deliverDelayedTouchEvent();
1792 qCDebug(lcTouchCmprs) <<
"resuming delivery" << event;
1794 deliverPointerEvent(event);
1799
1800
1801void QQuickDeliveryAgentPrivate::handleMouseEvent(QMouseEvent *event)
1803 Q_Q(QQuickDeliveryAgent);
1807 if (event->source() == Qt::MouseEventSynthesizedBySystem &&
1808 !(event->button() == Qt::RightButton && allowSyntheticRightClick())) {
1812 qCDebug(lcMouse) << q << event;
1814 switch (event->type()) {
1815 case QEvent::MouseButtonPress:
1816 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMousePress, event->button(),
1818 deliverPointerEvent(event);
1820 case QEvent::MouseButtonRelease:
1821 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseRelease, event->button(),
1823 deliverPointerEvent(event);
1824#if QT_CONFIG(cursor)
1825 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1828 case QEvent::MouseButtonDblClick:
1829 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseDoubleClick,
1830 event->button(), event->buttons());
1831 deliverPointerEvent(event);
1833 case QEvent::MouseMove: {
1834 Q_QUICK_INPUT_PROFILE(QQuickProfiler::Mouse, QQuickProfiler::InputMouseMove,
1835 event->position().x(), event->position().y());
1837 const QPointF last = lastMousePosition.isNull() ? event->scenePosition() : lastMousePosition;
1838 lastMousePosition = event->scenePosition();
1839 qCDebug(lcHoverTrace) << q << event <<
"mouse pos" << last <<
"->" << lastMousePosition;
1840 if (!event->points().size() || !event->exclusiveGrabber(event->point(0))) {
1841 bool accepted = deliverHoverEvent(event->scenePosition(), last, event->modifiers(), event->timestamp());
1842 event->setAccepted(accepted);
1844 deliverPointerEvent(event);
1845#if QT_CONFIG(cursor)
1847 QQuickWindowPrivate::get(rootItem->window())->updateCursor(event->scenePosition());
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872void QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents(QQuickWindow *win)
1874 Q_Q(QQuickDeliveryAgent);
1875 QQuickDeliveryAgent *deliveringAgent = QQuickDeliveryAgentPrivate::currentEventDeliveryAgent;
1876 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = q;
1879 deliverDelayedTouchEvent();
1883 QQmlAnimationTimer *ut = QQmlAnimationTimer::instance();
1884 if (ut && ut->hasStartAnimationPending())
1885 ut->startAnimations();
1890#if !defined(Q_OS_WEBOS)
1900 if (frameSynchronousHoverInterval >= 0) {
1901 const bool timerActive = frameSynchronousHoverInterval > 0;
1902 const bool timerMature = frameSynchronousHoverTimer.elapsed() >= frameSynchronousHoverInterval;
1903 if (timerActive && !timerMature) {
1904 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery delayed: elapsed"
1905 << frameSynchronousHoverTimer.elapsed() <<
"<" << frameSynchronousHoverInterval;
1906 if (!frameSynchronousDelayTimer.isActive())
1907 frameSynchronousDelayTimer.start(frameSynchronousHoverInterval - frameSynchronousHoverTimer.elapsed(), q);
1908 }
else if (!win->mouseGrabberItem() && !lastMousePosition.isNull() &&
1909 (timerMature || QQuickWindowPrivate::get(win)->dirtyItemList)) {
1910 frameSynchronousDelayTimer.stop();
1911 qCDebug(lcHoverTrace) << q <<
"delivering frame-sync hover to root @" << lastMousePosition
1912 <<
"after elapsed time" << frameSynchronousHoverTimer.elapsed();
1913 if (deliverHoverEvent(lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), 0)) {
1914#if QT_CONFIG(cursor)
1915 QQuickWindowPrivate::get(rootItem->window())->updateCursor(
1916 sceneTransform ? sceneTransform->map(lastMousePosition) : lastMousePosition, rootItem);
1921 frameSynchronousHoverTimer.restart();
1922 ++frameSynchronousHover_counter;
1923 qCDebug(lcHoverTrace) << q <<
"frame-sync hover delivery done: round" << frameSynchronousHover_counter;
1929 if (Q_UNLIKELY(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent &&
1930 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent != q))
1931 qCWarning(lcPtr,
"detected interleaved frame-sync and actual events");
1932 QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveringAgent;
1936
1937
1938
1939
1940
1941
1942
1943void QQuickDeliveryAgentPrivate::onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition,
1944 const QPointerEvent *event,
const QEventPoint &point)
1946 Q_Q(QQuickDeliveryAgent);
1947 const bool grabGained = (transition == QPointingDevice::GrabTransition::GrabExclusive ||
1948 transition == QPointingDevice::GrabTransition::GrabPassive);
1951 if (
auto *handler = qmlobject_cast<QQuickPointerHandler *>(grabber)) {
1952 if (handler->parentItem()) {
1953 auto itemPriv = QQuickItemPrivate::get(handler->parentItem());
1954 if (itemPriv->deliveryAgent() == q) {
1955 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1956 const_cast<QEventPoint &>(point));
1961 if (isSubsceneAgent && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
1962 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
1964 }
else if (!isSubsceneAgent) {
1965 handler->onGrabChanged(handler, transition,
const_cast<QPointerEvent *>(event),
1966 const_cast<QEventPoint &>(point));
1968 }
else if (
auto *grabberItem = qmlobject_cast<QQuickItem *>(grabber)) {
1969 switch (transition) {
1970 case QPointingDevice::CancelGrabExclusive:
1971 case QPointingDevice::UngrabExclusive:
1972 if (isDeliveringTouchAsMouse() || isSinglePointDevice(point.device())) {
1975 QMutableSinglePointEvent e(QEvent::UngrabMouse, point.device(), point);
1976 hasFiltered.clear();
1977 if (!sendFilteredMouseEvent(&e, grabberItem, grabberItem->parentItem())) {
1978 lastUngrabbed = grabberItem;
1979 grabberItem->mouseUngrabEvent();
1984 bool allReleasedOrCancelled =
true;
1985 if (transition == QPointingDevice::UngrabExclusive && event) {
1986 for (
const auto &pt : event->points()) {
1987 if (pt.state() != QEventPoint::State::Released) {
1988 allReleasedOrCancelled =
false;
1993 if (allReleasedOrCancelled)
1994 grabberItem->touchUngrabEvent();
2000 auto *itemPriv = QQuickItemPrivate::get(grabberItem);
2003 if (isSubsceneAgent && grabGained && (!itemPriv->extra.isAllocated() || !itemPriv->extra->subsceneDeliveryAgent))
2004 itemPriv->maybeHasSubsceneDeliveryAgent =
true;
2007 if (currentEventDeliveryAgent == q && event && event->device()) {
2008 switch (transition) {
2009 case QPointingDevice::GrabPassive: {
2010 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2012 QPointingDevicePrivate::setPassiveGrabberContext(epd, grabber, q);
2013 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2015 case QPointingDevice::GrabExclusive: {
2016 auto epd = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(event->pointingDevice()))->queryPointById(point.id());
2018 epd->exclusiveGrabberContext = q;
2019 qCDebug(lcPtr) <<
"remembering that" << q <<
"handles point" << point.id() <<
"after" << transition;
2021 case QPointingDevice::CancelGrabExclusive:
2022 case QPointingDevice::UngrabExclusive:
2025 case QPointingDevice::UngrabPassive:
2026 case QPointingDevice::CancelGrabPassive:
2029 case QPointingDevice::OverrideGrabPassive:
2037
2038
2039
2040
2041
2042
2043
2044
2045void QQuickDeliveryAgentPrivate::ensureDeviceConnected(
const QPointingDevice *dev)
2047 Q_Q(QQuickDeliveryAgent);
2048 if (knownPointingDevices.contains(dev))
2050 knownPointingDevices.append(dev);
2051 connect(dev, &QPointingDevice::grabChanged,
this, &QQuickDeliveryAgentPrivate::onGrabChanged);
2052 QObject::connect(dev, &QObject::destroyed, q, [
this, dev] {
this->knownPointingDevices.removeAll(dev);});
2056
2057
2058
2059
2060
2061
2062void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
2064 Q_Q(QQuickDeliveryAgent);
2065 if (isTabletEvent(event))
2066 qCDebug(lcTablet) << q << event;
2071 ++pointerEventRecursionGuard;
2072 eventsInDelivery.push(event);
2078 QVarLengthArray<QPointF, 16> originalScenePositions;
2079 if (sceneTransform) {
2080 originalScenePositions.resize(event->pointCount());
2081 for (
int i = 0; i < event->pointCount(); ++i) {
2082 auto &pt = event->point(i);
2083 originalScenePositions[i] = pt.scenePosition();
2084 QMutableEventPoint::setScenePosition(pt, sceneTransform->map(pt.scenePosition()));
2085 qCDebug(lcPtrLoc) << q << event->type() << pt.id() <<
"transformed scene pos" << pt.scenePosition();
2087 }
else if (isSubsceneAgent) {
2088 qCDebug(lcPtrLoc) << q << event->type() <<
"no scene transform set";
2091 skipDelivery.clear();
2092 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->pointingDevice()).clear();
2094 qCDebug(lcPtr) << q <<
"delivering with" << sceneTransform << event;
2096 qCDebug(lcPtr) << q <<
"delivering" << event;
2097 for (
int i = 0; i < event->pointCount(); ++i)
2098 event->point(i).setAccepted(
false);
2100 if (event->isBeginEvent()) {
2101 ensureDeviceConnected(event->pointingDevice());
2102 if (event->type() == QEvent::MouseButtonPress && rootItem->window()
2103 &&
static_cast<QSinglePointEvent *>(event)->button() == Qt::RightButton) {
2104 QQuickWindowPrivate::get(rootItem->window())->rmbContextMenuEventEnabled =
true;
2106 if (!deliverPressOrReleaseEvent(event))
2107 event->setAccepted(
false);
2110 auto isHoveringMoveEvent = [](QPointerEvent *event) ->
bool {
2111 if (event->type() == QEvent::MouseMove) {
2112 const auto *spe =
static_cast<
const QSinglePointEvent *>(event);
2113 if (spe->button() == Qt::NoButton && spe->buttons() == Qt::NoButton)
2120
2121
2122
2123
2124
2125
2126
2127
2128 if (!allUpdatedPointsAccepted(event) && !isHoveringMoveEvent(event))
2129 deliverUpdatedPoints(event);
2130 if (event->isEndEvent())
2131 deliverPressOrReleaseEvent(event,
true);
2135 if (isTouchEvent(event) && touchMouseId >= 0) {
2136 if (
static_cast<QTouchEvent *>(event)->touchPointStates() == QEventPoint::State::Released) {
2137 cancelTouchMouseSynthesis();
2139 auto touchMousePoint = event->pointById(touchMouseId);
2140 if (touchMousePoint && touchMousePoint->state() == QEventPoint::State::Released)
2141 cancelTouchMouseSynthesis();
2145 eventsInDelivery.pop();
2146 if (sceneTransform) {
2147 for (
int i = 0; i < event->pointCount(); ++i)
2148 QMutableEventPoint::setScenePosition(event->point(i), originalScenePositions.at(i));
2150 --pointerEventRecursionGuard;
2151 lastUngrabbed =
nullptr;
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2192QList<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
const QEvent *event,
int pointId,
2193 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate)
const
2195 QList<QQuickItem *> targets;
2196 auto itemPrivate = QQuickItemPrivate::get(item);
2201 if (item != rootItem && !itemPrivate->eventHandlingBounds().contains(localPos) &&
2202 itemPrivate->effectivelyClipsEventHandlingChildren()) {
2203 qCDebug(lcPtrLoc) <<
"skipping because" << localPos <<
"is outside rectangular bounds of" << item;
2209 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2214 Q_ASSERT(event->isPointerEvent());
2215 QPointerEvent *pev =
const_cast<QPointerEvent *>(
static_cast<
const QPointerEvent *>(event));
2216 QEventPoint *point = pev->pointById(pointId);
2218 QMutableEventPoint::setPosition(*point, localPos);
2220 const std::optional<
bool> override = predicate(item, event);
2221 const bool relevant = override.has_value() ? override.value()
2222 : item == rootItem || item->contains(localPos);
2224 auto it = std::lower_bound(children.begin(), children.end(), 0,
2225 [](
auto lhs,
auto rhs) ->
bool {
return lhs->z() < rhs; });
2226 children.insert(it, item);
2231 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2232 QQuickItem *child = children.at(ii);
2233 auto childPrivate = QQuickItemPrivate::get(child);
2234 if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
2235 (child != item && childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
2238 if (child == item) {
2241 QTransform childToParent;
2242 childPrivate->itemToParentTransform(&childToParent);
2243 const QPointF childLocalPos = childToParent.inverted().map(localPos);
2244 targets << eventTargets(child, event, pointId, childLocalPos, scenePos, predicate);
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280QList<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *item,
const QPointerEvent *event,
const QEventPoint &point,
2281 bool checkMouseButtons,
bool checkAcceptsTouch)
const
2283 auto predicate = [point, checkMouseButtons, checkAcceptsTouch](QQuickItem *item,
const QEvent *ev) -> std::optional<
bool> {
2284 const QPointerEvent *event =
static_cast<
const QPointerEvent *>(ev);
2285 auto itemPrivate = QQuickItemPrivate::get(item);
2286 if (itemPrivate->hasPointerHandlers()) {
2287 if (itemPrivate->anyPointerHandlerWants(event, point))
2290 if (checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
2292 if (checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
2296 return std::nullopt;
2299 return eventTargets(item, event, point.id(), item->mapFromScene(point.scenePosition()), point.scenePosition(), predicate);
2303
2304
2305
2306QList<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(
const QList<QQuickItem *> &list1,
const QList<QQuickItem *> &list2)
const
2308 QList<QQuickItem *> targets = list1;
2312 int insertPosition = targets.size();
2313 for (
int i = list2.size() - 1; i >= 0; --i) {
2314 int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
2315 if (newInsertPosition >= 0) {
2316 Q_ASSERT(newInsertPosition <= insertPosition);
2317 insertPosition = newInsertPosition;
2320 if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
2321 targets.insert(insertPosition, list2.at(i));
2327
2328
2329void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
2331 Q_Q(
const QQuickDeliveryAgent);
2333 const auto grabbers = exclusiveGrabbers(event);
2334 hasFiltered.clear();
2335 for (
auto grabber : grabbers) {
2337 QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
2340 QQuickPointerHandler *handler =
static_cast<QQuickPointerHandler *>(grabber);
2341 receiver =
static_cast<QQuickPointerHandler *>(grabber)->parentItem();
2345 hasFiltered.clear();
2346 if (sendFilteredPointerEvent(event, receiver))
2348 localizePointerEvent(event, receiver);
2350 handler->handlePointerEvent(event);
2356 hasFiltered.clear();
2358 deliverMatchingPointsToItem(receiver,
true, event);
2362 for (
auto &point : event->points()) {
2363 auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
2364 if (Q_UNLIKELY(!epd)) {
2365 qWarning() <<
"point is not in activePoints" << point;
2368 QList<QPointer<QObject>> relevantPassiveGrabbers;
2369 for (
int i = 0; i < epd->passiveGrabbersContext.size(); ++i) {
2370 if (epd->passiveGrabbersContext.at(i).data() == q)
2371 relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
2373 if (!relevantPassiveGrabbers.isEmpty())
2374 deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
2377 if (event->type() == QEvent::TouchUpdate) {
2378 for (
const auto &[item, id] : hoverItems) {
2380 bool res = deliverHoverEventToItem(item, item->mapFromScene(point.scenePosition()), point.scenePosition(), point.sceneLastPosition(),
2381 point.globalPosition(), event->modifiers(), event->timestamp(), HoverChange::Set);
2383 Q_ASSERT(([
this, item = item.get(), res]{
2384 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
2385 return !res || it2->hoverId != 0;
2396 if (!allPointsGrabbed(event)) {
2397 QList<QQuickItem *> targetItems;
2398 for (
auto &point : event->points()) {
2401 if (point.state() == QEventPoint::Pressed || qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(point)))
2403 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point,
false,
false);
2404 if (targetItems.size()) {
2405 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2407 targetItems = targetItemsForPoint;
2410 for (QQuickItem *item : targetItems) {
2411 if (grabbers.contains(item))
2413 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2414 localizePointerEvent(event, item);
2415 itemPrivate->handlePointerEvent(event,
true);
2416 if (allPointsGrabbed(event))
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event,
bool handlersOnly)
2463 QList<QQuickItem *> targetItems;
2464 const bool isTouch = isTouchEvent(event);
2465 if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) {
2466 if (
auto point =
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) {
2476 if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint)))
2477 cancelTouchMouseSynthesis();
2479 qCWarning(lcTouchTarget) <<
"during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId <<
"is missing from" << event;
2482 for (
int i = 0; i < event->pointCount(); ++i) {
2483 auto &point = event->point(i);
2487 if (isTouch && point.state() == QEventPoint::Pressed)
2488 resetIfDoubleTapPrevented(point);
2489 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch);
2490 if (targetItems.size()) {
2491 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2493 targetItems = targetItemsForPoint;
2497 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
2499 for (
auto &item : safeTargetItems) {
2503 if (isSubsceneAgent)
2504 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
2506 hasFiltered.clear();
2507 if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
2508 if (event->isAccepted())
2510 skipDelivery.append(item);
2515 if (skipDelivery.contains(item))
2520 for (
int i = 0; i < event->pointCount(); ++i)
2521 event->point(i).setAccepted(
false);
2523 deliverMatchingPointsToItem(item,
false, event, handlersOnly);
2524 if (event->allPointsAccepted())
2525 handlersOnly =
true;
2531 return handlersOnly;
2535
2536
2537
2538
2539
2540
2541
2542void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item,
bool isGrabber, QPointerEvent *pointerEvent,
bool handlersOnly)
2544 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2545#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
2550 if (itemPrivate->wasDeleted)
2553 localizePointerEvent(pointerEvent, item);
2554 bool isMouse = isMouseEvent(pointerEvent);
2558 if (pointerEvent->type() != QEvent::MouseButtonDblClick)
2559 itemPrivate->handlePointerEvent(pointerEvent);
2566 if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent()
2567 && !exclusiveGrabbers(pointerEvent).contains(item))
2571 if (sendFilteredPointerEvent(pointerEvent, item))
2577 auto button =
static_cast<QSinglePointEvent *>(pointerEvent)->button();
2578 if ((isGrabber && button == Qt::NoButton) || item->acceptedMouseButtons().testFlag(button)) {
2581 auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0));
2582 pointerEvent->accept();
2583 if (isGrabber && sendFilteredPointerEvent(pointerEvent, item))
2585 localizePointerEvent(pointerEvent, item);
2586 QCoreApplication::sendEvent(item, pointerEvent);
2587 if (pointerEvent->isAccepted()) {
2588 auto &point = pointerEvent->point(0);
2589 auto mouseGrabber = pointerEvent->exclusiveGrabber(point);
2590 if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
2596 if (item != lastUngrabbed) {
2597 item->mouseUngrabEvent();
2598 lastUngrabbed = item;
2600 }
else if (item->isEnabled() && item->isVisible() && point.state() == QEventPoint::State::Pressed) {
2601 pointerEvent->setExclusiveGrabber(point, item);
2603 point.setAccepted(
true);
2609 if (!isTouchEvent(pointerEvent))
2612 bool eventAccepted =
false;
2613 QMutableTouchEvent touchEvent;
2614 itemPrivate->localizedTouchEvent(
static_cast<QTouchEvent *>(pointerEvent),
false, &touchEvent);
2615 if (touchEvent.type() == QEvent::None)
2618 if (item->acceptTouchEvents()) {
2619 qCDebug(lcTouch) <<
"considering delivering" << &touchEvent <<
" to " << item;
2622 qCDebug(lcTouch) <<
"actually delivering" << &touchEvent <<
" to " << item;
2623 QCoreApplication::sendEvent(item, &touchEvent);
2624 eventAccepted = touchEvent.isAccepted();
2627 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2628 !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
2629 deliverTouchAsMouse(item, &touchEvent);
2633 Q_ASSERT(item->acceptTouchEvents());
2634 if (eventAccepted) {
2635 bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
2636 for (
int i = 0; i < touchEvent.pointCount(); ++i) {
2637 auto &point = touchEvent.point(i);
2639 point.setAccepted();
2641 if (isPressOrRelease && !(itemPrivate->deliveryAgent() && pointerEvent->exclusiveGrabber(point)))
2642 pointerEvent->setExclusiveGrabber(point, item);
2647 for (
const auto &point: touchEvent.points()) {
2648 if (point.state() == QEventPoint::State::Pressed) {
2649 if (pointerEvent->exclusiveGrabber(point) == item) {
2650 qCDebug(lcTouchTarget) <<
"TP" << Qt::hex << point.id() <<
"disassociated";
2651 pointerEvent->setExclusiveGrabber(point,
nullptr);
2658#if QT_CONFIG(quick_draganddrop)
2659void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
2661 QObject *formerTarget = grabber->target();
2662 grabber->resetTarget();
2663 QQuickDragGrabber::iterator grabItem = grabber->begin();
2664 if (grabItem != grabber->end()) {
2665 Q_ASSERT(event->type() != QEvent::DragEnter);
2666 if (event->type() == QEvent::Drop) {
2667 QDropEvent *e =
static_cast<QDropEvent *>(event);
2668 for (e->setAccepted(
false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
2669 QPointF p = (**grabItem)->mapFromScene(e->position().toPoint());
2670 QDropEvent translatedEvent(
2672 e->possibleActions(),
2676 QQuickDropEventEx::copyActions(&translatedEvent, *e);
2677 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2678 e->setAccepted(translatedEvent.isAccepted());
2679 e->setDropAction(translatedEvent.dropAction());
2680 grabber->setTarget(**grabItem);
2683 if (event->type() != QEvent::DragMove) {
2684 QDragLeaveEvent leaveEvent;
2685 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2686 QCoreApplication::sendEvent(**grabItem, &leaveEvent);
2687 grabber->ignoreList().clear();
2690 QDragMoveEvent *moveEvent =
static_cast<QDragMoveEvent *>(event);
2694 QVarLengthArray<QQuickItem*, 64> currentGrabItems;
2695 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2696 currentGrabItems.append(**grabItem);
2699 QDragEnterEvent enterEvent(
2700 moveEvent->position(),
2701 moveEvent->possibleActions(),
2702 moveEvent->mimeData(),
2703 moveEvent->buttons(),
2704 moveEvent->modifiers());
2705 QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
2706 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, ¤tGrabItems,
2709 for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
2710 int i = currentGrabItems.indexOf(**grabItem);
2712 currentGrabItems.remove(i);
2714 QDragMoveEvent translatedEvent(
2715 (**grabItem)->mapFromScene(moveEvent->position()),
2716 moveEvent->possibleActions(),
2717 moveEvent->mimeData(),
2718 moveEvent->buttons(),
2719 moveEvent->modifiers());
2720 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
2721 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2722 event->setAccepted(translatedEvent.isAccepted());
2723 QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
2728 QDragLeaveEvent leaveEvent;
2729 for (QQuickItem *i : currentGrabItems)
2730 QCoreApplication::sendEvent(i, &leaveEvent);
2735 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
2736 QDragMoveEvent *e =
static_cast<QDragMoveEvent *>(event);
2737 QDragEnterEvent enterEvent(
2739 e->possibleActions(),
2743 QQuickDropEventEx::copyActions(&enterEvent, *e);
2744 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
2746 grabber->ignoreList().clear();
2750bool QQuickDeliveryAgentPrivate::deliverDragEvent(
2751 QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
2752 QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
2754 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2755 if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
2757 QPointF p = item->mapFromScene(event->position().toPoint());
2758 bool itemContained = item->contains(p);
2760 const int itemIndex = grabber->ignoreList().indexOf(item);
2761 if (!itemContained) {
2763 grabber->ignoreList().remove(itemIndex);
2765 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
2769 QDragEnterEvent enterEvent(
2771 event->possibleActions(),
2774 event->modifiers());
2775 QQuickDropEventEx::copyActions(&enterEvent, *event);
2776 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2779 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2780 if (children.at(ii)->z() < 0)
2782 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2786 if (itemContained) {
2789 if (currentGrabItems && currentGrabItems->contains(item)) {
2790 grabber->grab(item);
2791 grabber->setTarget(item);
2795 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
2796 if (event->type() == QEvent::DragEnter) {
2798 QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
2799 if (formerTargetItem && currentGrabItems) {
2800 QDragLeaveEvent leaveEvent;
2801 QCoreApplication::sendEvent(formerTarget, &leaveEvent);
2805 currentGrabItems->removeAll(formerTarget);
2807 }
else if (itemIndex >= 0) {
2812 QDragMoveEvent translatedEvent(p, event->possibleActions(), event->mimeData(),
2813 event->buttons(), event->modifiers(), event->type());
2814 QQuickDropEventEx::copyActions(&translatedEvent, *event);
2815 translatedEvent.setAccepted(event->isAccepted());
2816 QCoreApplication::sendEvent(item, &translatedEvent);
2817 event->setAccepted(translatedEvent.isAccepted());
2818 event->setDropAction(translatedEvent.dropAction());
2819 if (event->type() == QEvent::DragEnter) {
2820 if (translatedEvent.isAccepted()) {
2821 grabber->grab(item);
2822 grabber->setTarget(item);
2824 }
else if (itemIndex < 0) {
2825 grabber->ignoreList().append(item);
2834 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2835 if (children.at(ii)->z() >= 0)
2837 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2846
2847
2848
2849
2850
2851
2852
2853bool QQuickDeliveryAgentPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2855 return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
2859
2860
2861bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2863 if (!allowChildEventFiltering)
2865 if (!filteringParent)
2867 bool filtered =
false;
2868 const bool hasHandlers = QQuickItemPrivate::get(receiver)->hasPointerHandlers();
2869 if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
2870 hasFiltered.append(filteringParent);
2871 if (isMouseEvent(event)) {
2872 if (receiver->acceptedMouseButtons()) {
2873 const bool wasAccepted = event->allPointsAccepted();
2874 Q_ASSERT(event->pointCount());
2875 localizePointerEvent(event, receiver);
2876 event->setAccepted(
true);
2877 auto oldMouseGrabber = event->exclusiveGrabber(event->point(0));
2878 if (filteringParent->childMouseEventFilter(receiver, event)) {
2879 qCDebug(lcMouse) <<
"mouse event intercepted by childMouseEventFilter of " << filteringParent;
2880 skipDelivery.append(filteringParent);
2882 if (event->isAccepted() && event->isBeginEvent()) {
2883 auto &point = event->point(0);
2884 auto mouseGrabber = event->exclusiveGrabber(point);
2885 if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
2886 receiver->mouseUngrabEvent();
2888 event->setExclusiveGrabber(point, receiver);
2893 event->setAccepted(wasAccepted);
2896 }
else if (isTouchEvent(event)) {
2897 const bool acceptsTouchEvents = receiver->acceptTouchEvents() || hasHandlers;
2898 auto device = event->device();
2899 if (device->type() == QInputDevice::DeviceType::TouchPad &&
2900 device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
2901 qCDebug(lcTouchTarget) <<
"skipping filtering of synth-mouse event from" << device;
2902 }
else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
2905 QMutableTouchEvent filteringParentTouchEvent;
2906 QQuickItemPrivate::get(receiver)->localizedTouchEvent(
static_cast<QTouchEvent *>(event),
true, &filteringParentTouchEvent);
2907 if (filteringParentTouchEvent.type() != QEvent::None) {
2908 qCDebug(lcTouch) <<
"letting parent" << filteringParent <<
"filter for" << receiver << &filteringParentTouchEvent;
2909 filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent);
2911 qCDebug(lcTouch) <<
"touch event intercepted by childMouseEventFilter of " << filteringParent;
2912 event->setAccepted(filteringParentTouchEvent.isAccepted());
2913 skipDelivery.append(filteringParent);
2914 if (event->isAccepted()) {
2915 for (
auto point : filteringParentTouchEvent.points()) {
2916 const QQuickItem *exclusiveGrabber = qobject_cast<
const QQuickItem *>(event->exclusiveGrabber(point));
2917 if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab())
2918 event->setExclusiveGrabber(point, filteringParent);
2921 }
else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2922 !filteringParent->acceptTouchEvents()) {
2923 qCDebug(lcTouch) <<
"touch event NOT intercepted by childMouseEventFilter of " << filteringParent
2924 <<
"; accepts touch?" << filteringParent->acceptTouchEvents()
2925 <<
"receiver accepts touch?" << acceptsTouchEvents
2926 <<
"so, letting parent filter a synth-mouse event";
2928 for (
auto &tp : filteringParentTouchEvent.points()) {
2930 switch (tp.state()) {
2931 case QEventPoint::State::Pressed:
2932 t = QEvent::MouseButtonPress;
2934 case QEventPoint::State::Released:
2935 t = QEvent::MouseButtonRelease;
2937 case QEventPoint::State::Stationary:
2940 t = QEvent::MouseMove;
2944 bool touchMouseUnset = (touchMouseId == -1);
2946 if (touchMouseUnset || touchMouseId == tp.id()) {
2949 QMutableSinglePointEvent mouseEvent;
2950 touchToMouseEvent(t, tp, &filteringParentTouchEvent, &mouseEvent);
2954 touchMouseId = tp.id();
2955 touchMouseDevice = event->pointingDevice();
2956 filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent);
2958 qCDebug(lcTouch) <<
"touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
2959 event->setAccepted(mouseEvent.isAccepted());
2960 skipDelivery.append(filteringParent);
2961 if (event->isAccepted() && event->isBeginEvent()) {
2962 qCDebug(lcTouchTarget) <<
"TP (mouse)" << Qt::hex << tp.id() <<
"->" << filteringParent;
2963 filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent);
2964 touchMouseUnset =
false;
2965 filteringParent->grabMouse();
2968 if (touchMouseUnset)
2971 cancelTouchMouseSynthesis();
2972 mouseEvent.point(0).setAccepted(
false);
2983 return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997bool QQuickDeliveryAgentPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2999 if (!filteringParent)
3002 QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
3003 if (filteringParentPrivate->replayingPressEvent)
3006 bool filtered =
false;
3007 if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
3008 hasFiltered.append(filteringParent);
3009 if (filteringParent->childMouseEventFilter(receiver, event)) {
3011 skipDelivery.append(filteringParent);
3013 qCDebug(lcMouseTarget) <<
"for" << receiver << filteringParent <<
"childMouseEventFilter ->" << filtered;
3016 return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
3020
3021
3022
3023
3024
3025
3026bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event,
int startDragThreshold)
3028 QStyleHints *styleHints = QGuiApplication::styleHints();
3029 bool dragVelocityLimitAvailable = event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
3030 && styleHints->startDragVelocity();
3031 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3032 if (dragVelocityLimitAvailable) {
3033 QVector2D velocityVec = event->point(0).velocity();
3034 qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
3035 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3037 return overThreshold;
3041
3042
3043
3044
3045
3046
3047bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const QEventPoint &tp,
int startDragThreshold)
3049 QStyleHints *styleHints = qApp->styleHints();
3050 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3051 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
3052 if (!overThreshold && dragVelocityLimitAvailable) {
3053 qreal velocity = axis == Qt::XAxis ? tp.velocity().x() : tp.velocity().y();
3054 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3056 return overThreshold;
3060
3061
3062
3063
3064bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
3066 int threshold = qApp->styleHints()->startDragDistance();
3067 return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
3071
3072
3073
3074
3075
3076
3077QList<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item,
const QContextMenuEvent *event)
const
3079 auto predicate = [](QQuickItem *,
const QEvent *) -> std::optional<
bool> {
3080 return std::nullopt;
3083 const auto pos = event->pos().isNull() ? activeFocusItem->mapToScene({}).toPoint() : event->pos();
3084 if (event->pos().isNull())
3085 qCDebug(lcContextMenu) <<
"for QContextMenuEvent, active focus item is" << activeFocusItem <<
"@" << pos;
3086 return eventTargets(item, event, -1, pos, pos, predicate);
3090
3091
3092
3093
3094void QQuickDeliveryAgentPrivate::deliverContextMenuEvent(QContextMenuEvent *event)
3096 skipDelivery.clear();
3097 QList<QQuickItem *> targetItems = contextMenuTargets(rootItem, event);
3098 qCDebug(lcContextMenu) <<
"delivering context menu event" << event <<
"to" << targetItems.size() <<
"target item(s)";
3099 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
3100 for (
auto &item : safeTargetItems) {
3101 qCDebug(lcContextMenu) <<
"- attempting to deliver to" << item;
3105 if (isSubsceneAgent)
3106 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
3108 QCoreApplication::sendEvent(item, event);
3109 if (event->isAccepted())
3114#ifndef QT_NO_DEBUG_STREAM
3117 QDebugStateSaver saver(debug);
3120 debug <<
"QQuickDeliveryAgent(0)";
3124 debug <<
"QQuickDeliveryAgent(";
3125 if (!da->objectName().isEmpty())
3126 debug << da->objectName() <<
' ';
3127 auto root = da->rootItem();
3128 if (Q_LIKELY(root)) {
3129 debug <<
"root=" << root->metaObject()->className();
3130 if (!root->objectName().isEmpty())
3131 debug <<
' ' << root->objectName();
3142#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)