5#include <QtCore/qdebug.h>
6#include <QtGui/private/qevent_p.h>
7#include <QtGui/private/qeventpoint_p.h>
8#include <QtGui/private/qguiapplication_p.h>
9#include <QtGui/qpa/qplatformtheme.h>
10#include <QtQml/private/qabstractanimationjob_p.h>
11#include <QtQuick/private/qquickdeliveryagent_p_p.h>
12#include <QtQuick/private/qquickhoverhandler_p.h>
13#include <QtQuick/private/qquickpointerhandler_p_p.h>
14#if QT_CONFIG(quick_draganddrop)
15#include <QtQuick/private/qquickdrag_p.h>
17#include <QtQuick/private/qquickitem_p.h>
18#include <QtQuick/private/qquickprofiler_p.h>
19#include <QtQuick/private/qquickrendercontrol_p.h>
20#include <QtQuick/private/qquickwindow_p.h>
22#include <QtCore/qpointer.h>
30Q_STATIC_LOGGING_CATEGORY(lcTouchCmprs,
"qt.quick.touch.compression")
31Q_LOGGING_CATEGORY(lcTouchTarget,
"qt.quick.touch.target")
32Q_LOGGING_CATEGORY(lcMouse,
"qt.quick.mouse")
33Q_STATIC_LOGGING_CATEGORY(lcMouseTarget,
"qt.quick.mouse.target")
34Q_STATIC_LOGGING_CATEGORY(lcTablet,
"qt.quick.tablet")
35Q_LOGGING_CATEGORY(lcPtr,
"qt.quick.pointer")
36Q_STATIC_LOGGING_CATEGORY(lcPtrLoc,
"qt.quick.pointer.localization")
37Q_STATIC_LOGGING_CATEGORY(lcWheelTarget,
"qt.quick.wheel.target")
38Q_LOGGING_CATEGORY(lcHoverTrace,
"qt.quick.hover.trace")
39Q_LOGGING_CATEGORY(lcHoverCursor,
"qt.quick.hover.cursor")
40Q_LOGGING_CATEGORY(lcFocus,
"qt.quick.focus")
41Q_STATIC_LOGGING_CATEGORY(lcContextMenu,
"qt.quick.contextmenu")
45bool QQuickDeliveryAgentPrivate::subsceneAgentsExist(
false);
46QQuickDeliveryAgent *QQuickDeliveryAgentPrivate::currentEventDeliveryAgent(
nullptr);
50 static int allowRightClick = -1;
51 if (allowRightClick < 0) {
53 allowRightClick = qEnvironmentVariableIntValue(
"QT_QUICK_ALLOW_SYNTHETIC_RIGHT_CLICK", &ok);
57 return allowRightClick != 0;
62 return std::find_if(hoverItems.begin(), hoverItems.end(),
63 [item](
const QQuickDeliveryAgentPrivate::HoverItemState &hoverState) {
64 return hoverState.item == item;
70 return std::find_if(hoverItems.cbegin(), hoverItems.cend(),
71 [item](
const QQuickDeliveryAgentPrivate::HoverItemState &hoverState) {
72 return hoverState.item == item;
76void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type,
const QEventPoint &p,
const QTouchEvent *touchEvent, QMutableSinglePointEvent *mouseEvent)
78 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
79 QMutableSinglePointEvent ret(type, touchEvent->pointingDevice(), p,
80 (type == QEvent::MouseMove ? Qt::NoButton : Qt::LeftButton),
81 (type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton),
82 touchEvent->modifiers(), Qt::MouseEventSynthesizedByQt);
83 ret.setAccepted(
true);
84 ret.setTimestamp(touchEvent->timestamp());
88 Q_ASSERT(mouseEvent->device() == touchEvent->device());
89 if (Q_UNLIKELY(mouseEvent->device()->type() == QInputDevice::DeviceType::Mouse))
90 qWarning() <<
"Unexpected: synthesized an indistinguishable mouse event" << mouseEvent;
94
95
96bool QQuickDeliveryAgentPrivate::isWithinDoubleClickInterval(ulong timeInterval)
98 return timeInterval <
static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
102
103
104bool QQuickDeliveryAgentPrivate::isWithinDoubleTapDistance(
const QPoint &distanceBetweenPresses)
106 auto square = [](qint64 v) {
return v * v; };
107 return square(distanceBetweenPresses.x()) + square(distanceBetweenPresses.y()) <
108 square(QGuiApplication::styleHints()->touchDoubleTapDistance());
111bool QQuickDeliveryAgentPrivate::checkIfDoubleTapped(ulong newPressEventTimestamp,
const QPoint &newPressPos)
113 const bool doubleClicked = isDeliveringTouchAsMouse() &&
114 isWithinDoubleTapDistance(newPressPos - touchMousePressPos) &&
115 isWithinDoubleClickInterval(newPressEventTimestamp - touchMousePressTimestamp);
117 touchMousePressTimestamp = 0;
119 touchMousePressTimestamp = newPressEventTimestamp;
120 touchMousePressPos = newPressPos;
122 return doubleClicked;
125void QQuickDeliveryAgentPrivate::resetIfDoubleTapPrevented(
const QEventPoint &pressedPoint)
127 if (touchMousePressTimestamp > 0 &&
128 (!isWithinDoubleTapDistance(pressedPoint.globalPosition().toPoint() - touchMousePressPos) ||
129 !isWithinDoubleClickInterval(pressedPoint.timestamp() - touchMousePressTimestamp))) {
130 touchMousePressTimestamp = 0;
131 touchMousePressPos = QPoint();
136
137
138
139
140
141
142
143QPointerEvent *QQuickDeliveryAgentPrivate::eventInDelivery()
const
145 if (eventsInDelivery.isEmpty())
147 return eventsInDelivery.top();
151
152
153
154
155QPointingDevicePrivate::EventPointData *QQuickDeliveryAgentPrivate::mousePointData()
157 if (eventsInDelivery.isEmpty())
159 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice*>(eventsInDelivery.top()->pointingDevice()));
160 return devPriv->pointById(isDeliveringTouchAsMouse() ? touchMouseId : 0);
163void QQuickDeliveryAgentPrivate::cancelTouchMouseSynthesis()
165 qCDebug(lcTouchTarget) <<
"id" << touchMouseId <<
"on" << touchMouseDevice;
167 touchMouseDevice =
nullptr;
170bool QQuickDeliveryAgentPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEvent *pointerEvent)
172 Q_Q(QQuickDeliveryAgent);
173 Q_ASSERT(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents));
174 auto device = pointerEvent->pointingDevice();
177 if (device->type() == QInputDevice::DeviceType::TouchPad && device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
178 qCDebug(lcTouchTarget) << q <<
"skipping delivery of synth-mouse event from" << device;
183 QMutableTouchEvent event;
184 QQuickItemPrivate::get(item)->localizedTouchEvent(pointerEvent,
false, &event);
185 if (!event.points().size())
191 for (
auto &p : event.points()) {
193 if (touchMouseId == -1 && p.state() & QEventPoint::State::Pressed) {
194 QPointF pos = item->mapFromScene(p.scenePosition());
197 if (!item->contains(pos))
200 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << item;
201 QMutableSinglePointEvent mousePress;
202 touchToMouseEvent(QEvent::MouseButtonPress, p, &event, &mousePress);
205 QCoreApplication::sendEvent(item, &mousePress);
206 event.setAccepted(mousePress.isAccepted());
207 if (mousePress.isAccepted()) {
208 touchMouseDevice = device;
209 touchMouseId = p.id();
210 const auto &pt = mousePress.point(0);
211 if (!mousePress.exclusiveGrabber(pt))
212 mousePress.setExclusiveGrabber(pt, item);
214 if (checkIfDoubleTapped(event.timestamp(), p.globalPosition().toPoint())) {
217 QMutableSinglePointEvent mouseDoubleClick;
218 touchToMouseEvent(QEvent::MouseButtonDblClick, p, &event, &mouseDoubleClick);
219 QCoreApplication::sendEvent(item, &mouseDoubleClick);
220 event.setAccepted(mouseDoubleClick.isAccepted());
221 if (!mouseDoubleClick.isAccepted())
222 cancelTouchMouseSynthesis();
230 }
else if (touchMouseDevice == device && p.id() == touchMouseId) {
231 if (p.state() & QEventPoint::State::Updated) {
232 if (touchMousePressTimestamp != 0) {
233 if (!isWithinDoubleTapDistance(p.globalPosition().toPoint() - touchMousePressPos))
234 touchMousePressTimestamp = 0;
236 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
237 QMutableSinglePointEvent me;
238 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
239 QCoreApplication::sendEvent(item, &me);
240 event.setAccepted(me.isAccepted());
242 qCDebug(lcTouchTarget) << q << device <<
"TP (mouse)" << Qt::hex << p.id() <<
"->" << mouseGrabberItem;
243 return event.isAccepted();
248 QMutableSinglePointEvent me;
249 touchToMouseEvent(QEvent::MouseMove, p, &event, &me);
250 if (lastMousePosition.isNull())
251 lastMousePosition = me.scenePosition();
252 QPointF last = lastMousePosition;
253 lastMousePosition = me.scenePosition();
255 deliverHoverEvent(me.scenePosition(), last, me.modifiers(), me.timestamp());
258 }
else if (p.state() & QEventPoint::State::Released) {
260 if (QQuickItem *mouseGrabberItem = qmlobject_cast<QQuickItem *>(pointerEvent->exclusiveGrabber(p))) {
261 QMutableSinglePointEvent me;
262 touchToMouseEvent(QEvent::MouseButtonRelease, p, &event, &me);
263 QCoreApplication::sendEvent(item, &me);
265 if (item->acceptHoverEvents() && p.globalPosition() != QGuiApplicationPrivate::lastCursorPosition) {
266 QPointF localMousePos(qInf(), qInf());
267 if (QWindow *w = item->window())
268 localMousePos = item->mapFromScene(w->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition));
269 QMouseEvent mm(QEvent::MouseMove, localMousePos, QGuiApplicationPrivate::lastCursorPosition,
270 Qt::NoButton, Qt::NoButton, event.modifiers());
271 QCoreApplication::sendEvent(item, &mm);
273 if (pointerEvent->exclusiveGrabber(p) == mouseGrabberItem)
274 pointerEvent->setExclusiveGrabber(p,
nullptr);
276 cancelTouchMouseSynthesis();
277 return me.isAccepted();
287
288
289
290
291
292
293
294
295void QQuickDeliveryAgentPrivate::removeGrabber(QQuickItem *grabber,
bool mouse,
bool touch,
bool cancel)
297 Q_Q(QQuickDeliveryAgent);
298 if (eventsInDelivery.isEmpty()) {
300 for (
auto dev : knownPointingDevices) {
301 auto devPriv = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(dev));
302 devPriv->removeGrabber(grabber, cancel);
306 auto eventInDelivery = eventsInDelivery.top();
307 if (Q_LIKELY(mouse) && eventInDelivery) {
308 auto epd = mousePointData();
309 if (epd && epd->exclusiveGrabber == grabber && epd->exclusiveGrabberContext.data() == q) {
310 QQuickItem *oldGrabber = qobject_cast<QQuickItem *>(epd->exclusiveGrabber);
311 qCDebug(lcMouseTarget) <<
"removeGrabber" << oldGrabber <<
"-> null";
312 eventInDelivery->setExclusiveGrabber(epd->eventPoint,
nullptr);
315 if (Q_LIKELY(touch)) {
317 const auto touchDevices = QPointingDevice::devices();
318 for (
auto device : touchDevices) {
319 if (device->type() != QInputDevice::DeviceType::TouchScreen)
321 if (QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(
static_cast<
const QPointingDevice *>(device)))->
322 removeExclusiveGrabber(eventInDelivery, grabber))
326 grabber->touchUngrabEvent();
331
332
333
334
335
336
337
338
339
340
341
342void QQuickDeliveryAgentPrivate::clearGrabbers(QPointerEvent *pointerEvent)
344 if (pointerEvent->isEndEvent()
345 && !(isTabletEvent(pointerEvent)
346 && (qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)
347 || QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse))) {
348 if (pointerEvent->isSinglePointEvent()) {
349 if (
static_cast<QSinglePointEvent *>(pointerEvent)->buttons() == Qt::NoButton) {
350 auto &firstPt = pointerEvent->point(0);
351 pointerEvent->setExclusiveGrabber(firstPt,
nullptr);
352 pointerEvent->clearPassiveGrabbers(firstPt);
355 for (
auto &point : pointerEvent->points()) {
356 if (point.state() == QEventPoint::State::Released) {
357 pointerEvent->setExclusiveGrabber(point,
nullptr);
358 pointerEvent->clearPassiveGrabbers(point);
366
367
368
369
370void QQuickDeliveryAgentPrivate::translateTouchEvent(QTouchEvent *touchEvent)
372 for (qsizetype i = 0; i != touchEvent->pointCount(); ++i) {
373 auto &pt = touchEvent->point(i);
374 QMutableEventPoint::setScenePosition(pt, pt.position());
381 const QWindow *focusWindow = QGuiApplication::focusWindow();
382 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, device, [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
2191QList<QQuickItem *> QQuickDeliveryAgentPrivate::eventTargets(QQuickItem *item,
const QEvent *event,
int pointId,
2192 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate)
const
2194 QList<QQuickItem *> targets;
2195 eventTargetsAppend(item, event, pointId, localPos, scenePos, predicate, targets);
2200
2201
2202
2203
2204
2206void QQuickDeliveryAgentPrivate::eventTargetsAppend(QQuickItem *item,
const QEvent *event,
int pointId,
2207 QPointF localPos, QPointF scenePos, qxp::function_ref<std::optional<
bool> (QQuickItem *,
const QEvent *)> predicate,
2208 QList<QQuickItem *> &targets)
const
2210 auto itemPrivate = QQuickItemPrivate::get(item);
2215 if (item != rootItem && !itemPrivate->eventHandlingBounds().contains(localPos) &&
2216 itemPrivate->effectivelyClipsEventHandlingChildren()) {
2217 qCDebug(lcPtrLoc) <<
"skipping because" << localPos <<
"is outside rectangular bounds of" << item;
2223 const QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2228 Q_ASSERT(event->isPointerEvent());
2229 QPointerEvent *pev =
const_cast<QPointerEvent *>(
static_cast<
const QPointerEvent *>(event));
2230 QEventPoint *point = pev->pointById(pointId);
2232 QMutableEventPoint::setPosition(*point, localPos);
2234 const std::optional<
bool> override = predicate(item, event);
2235 const bool relevant = override.has_value() ? override.value()
2236 : item == rootItem || item->contains(localPos);
2241 bool selfEmitted = !relevant;
2242 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2243 QQuickItem *child = children.at(ii);
2244 if (!selfEmitted && child->z() < 0) {
2245 targets.append(item);
2249 auto childPrivate = QQuickItemPrivate::get(child);
2250 if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
2251 (childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
2254 QTransform childToParent;
2255 childPrivate->itemToParentTransform(&childToParent);
2256 const QPointF childLocalPos = childToParent.inverted().map(localPos);
2257 eventTargetsAppend(child, event, pointId, childLocalPos, scenePos, predicate, targets);
2262 targets.append(item);
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294QList<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *item,
const QPointerEvent *event,
const QEventPoint &point,
2295 bool checkMouseButtons,
bool checkAcceptsTouch)
const
2297 auto predicate = [point, checkMouseButtons, checkAcceptsTouch](QQuickItem *item,
const QEvent *ev) -> std::optional<
bool> {
2298 const QPointerEvent *event =
static_cast<
const QPointerEvent *>(ev);
2299 auto itemPrivate = QQuickItemPrivate::get(item);
2300 if (itemPrivate->hasPointerHandlers()) {
2301 if (itemPrivate->anyPointerHandlerWants(event, point))
2304 if (checkMouseButtons && item->acceptedMouseButtons() == Qt::NoButton)
2306 if (checkAcceptsTouch && !(item->acceptTouchEvents() || item->acceptedMouseButtons()))
2310 return std::nullopt;
2313 return eventTargets(item, event, point.id(), item->mapFromScene(point.scenePosition()), point.scenePosition(), predicate);
2317
2318
2319
2320QList<QQuickItem *> QQuickDeliveryAgentPrivate::mergePointerTargets(
const QList<QQuickItem *> &list1,
const QList<QQuickItem *> &list2)
const
2322 QList<QQuickItem *> targets = list1;
2326 int insertPosition = targets.size();
2327 for (
int i = list2.size() - 1; i >= 0; --i) {
2328 int newInsertPosition = targets.lastIndexOf(list2.at(i), insertPosition);
2329 if (newInsertPosition >= 0) {
2330 Q_ASSERT(newInsertPosition <= insertPosition);
2331 insertPosition = newInsertPosition;
2334 if (insertPosition == targets.size() || list2.at(i) != targets.at(insertPosition))
2335 targets.insert(insertPosition, list2.at(i));
2341
2342
2343void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
2345 Q_Q(
const QQuickDeliveryAgent);
2347 const auto grabbers = exclusiveGrabbers(event);
2348 hasFiltered.clear();
2349 for (
auto grabber : grabbers) {
2351 QQuickItem *receiver = qmlobject_cast<QQuickItem *>(grabber);
2354 QQuickPointerHandler *handler =
static_cast<QQuickPointerHandler *>(grabber);
2355 receiver =
static_cast<QQuickPointerHandler *>(grabber)->parentItem();
2359 hasFiltered.clear();
2360 if (sendFilteredPointerEvent(event, receiver))
2362 localizePointerEvent(event, receiver);
2364 handler->handlePointerEvent(event);
2370 hasFiltered.clear();
2372 deliverMatchingPointsToItem(receiver,
true, event);
2376 for (
auto &point : event->points()) {
2377 auto epd = QPointingDevicePrivate::get(event->pointingDevice())->queryPointById(point.id());
2378 if (Q_UNLIKELY(!epd)) {
2379 qWarning() <<
"point is not in activePoints" << point;
2382 QList<QPointer<QObject>> relevantPassiveGrabbers;
2383 for (
int i = 0; i < epd->passiveGrabbersContext.size(); ++i) {
2384 if (epd->passiveGrabbersContext.at(i).data() == q)
2385 relevantPassiveGrabbers << epd->passiveGrabbers.at(i);
2387 if (!relevantPassiveGrabbers.isEmpty())
2388 deliverToPassiveGrabbers(relevantPassiveGrabbers, event);
2391 if (event->type() == QEvent::TouchUpdate) {
2392 for (
const auto &[item, id] : hoverItems) {
2394 bool res = deliverHoverEventToItem(item, item->mapFromScene(point.scenePosition()), point.scenePosition(), point.sceneLastPosition(),
2395 point.globalPosition(), event->modifiers(), event->timestamp(), HoverChange::Set);
2397 Q_ASSERT(([
this, item = item.get(), res]{
2398 const auto it2 = findHoverStateByItem(std::as_const(hoverItems), item);
2399 return !res || it2->hoverId != 0;
2410 if (!allPointsGrabbed(event)) {
2411 QList<QQuickItem *> targetItems;
2412 for (
auto &point : event->points()) {
2415 if (point.state() == QEventPoint::Pressed || qmlobject_cast<QQuickItem *>(event->exclusiveGrabber(point)))
2417 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point,
false,
false);
2418 if (targetItems.size()) {
2419 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2421 targetItems = targetItemsForPoint;
2424 for (QQuickItem *item : targetItems) {
2425 if (grabbers.contains(item))
2427 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2428 localizePointerEvent(event, item);
2429 itemPrivate->handlePointerEvent(event,
true);
2430 if (allPointsGrabbed(event))
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475bool QQuickDeliveryAgentPrivate::deliverPressOrReleaseEvent(QPointerEvent *event,
bool handlersOnly)
2477 QList<QQuickItem *> targetItems;
2478 const bool isTouch = isTouchEvent(event);
2479 if (isTouch && event->isBeginEvent() && isDeliveringTouchAsMouse()) {
2480 if (
auto point =
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(touchMouseDevice))->queryPointById(touchMouseId)) {
2490 if (qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point->eventPoint)))
2491 cancelTouchMouseSynthesis();
2493 qCWarning(lcTouchTarget) <<
"during delivery of touch press, synth-mouse ID" << Qt::hex << touchMouseId <<
"is missing from" << event;
2496 for (
int i = 0; i < event->pointCount(); ++i) {
2497 auto &point = event->point(i);
2501 if (isTouch && point.state() == QEventPoint::Pressed)
2502 resetIfDoubleTapPrevented(point);
2503 QList<QQuickItem *> targetItemsForPoint = pointerTargets(rootItem, event, point, !isTouch, isTouch);
2504 if (targetItems.size()) {
2505 targetItems = mergePointerTargets(targetItems, targetItemsForPoint);
2507 targetItems = targetItemsForPoint;
2511 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
2513 for (
auto &item : safeTargetItems) {
2517 if (isSubsceneAgent)
2518 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
2520 hasFiltered.clear();
2521 if (!handlersOnly && sendFilteredPointerEvent(event, item)) {
2522 if (event->isAccepted())
2524 skipDelivery.append(item);
2529 if (skipDelivery.contains(item))
2534 for (
int i = 0; i < event->pointCount(); ++i)
2535 event->point(i).setAccepted(
false);
2537 deliverMatchingPointsToItem(item,
false, event, handlersOnly);
2538 if (event->allPointsAccepted())
2539 handlersOnly =
true;
2545 return handlersOnly;
2549
2550
2551
2552
2553
2554
2555
2556void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item,
bool isGrabber, QPointerEvent *pointerEvent,
bool handlersOnly)
2558 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2559#if defined(Q_OS_ANDROID) && QT_VERSION < QT_VERSION_CHECK(6
, 0
, 0
)
2564 if (itemPrivate->wasDeleted)
2567 localizePointerEvent(pointerEvent, item);
2568 bool isMouse = isMouseEvent(pointerEvent);
2572 if (pointerEvent->type() != QEvent::MouseButtonDblClick)
2573 itemPrivate->handlePointerEvent(pointerEvent);
2580 if (pointerEvent->isEndEvent() && !pointerEvent->isUpdateEvent()
2581 && !exclusiveGrabbers(pointerEvent).contains(item))
2585 if (sendFilteredPointerEvent(pointerEvent, item))
2591 auto button =
static_cast<QSinglePointEvent *>(pointerEvent)->button();
2592 if ((isGrabber && button == Qt::NoButton) || item->acceptedMouseButtons().testFlag(button)) {
2595 auto oldMouseGrabber = pointerEvent->exclusiveGrabber(pointerEvent->point(0));
2596 pointerEvent->accept();
2597 if (isGrabber && sendFilteredPointerEvent(pointerEvent, item))
2599 localizePointerEvent(pointerEvent, item);
2600 QCoreApplication::sendEvent(item, pointerEvent);
2601 if (pointerEvent->isAccepted()) {
2602 auto &point = pointerEvent->point(0);
2603 auto mouseGrabber = pointerEvent->exclusiveGrabber(point);
2604 if (mouseGrabber && mouseGrabber != item && mouseGrabber != oldMouseGrabber) {
2610 if (item != lastUngrabbed) {
2611 item->mouseUngrabEvent();
2612 lastUngrabbed = item;
2614 }
else if (item->isEnabled() && item->isVisible() && point.state() == QEventPoint::State::Pressed) {
2615 pointerEvent->setExclusiveGrabber(point, item);
2617 point.setAccepted(
true);
2623 if (!isTouchEvent(pointerEvent))
2626 bool eventAccepted =
false;
2627 QMutableTouchEvent touchEvent;
2628 itemPrivate->localizedTouchEvent(
static_cast<QTouchEvent *>(pointerEvent),
false, &touchEvent);
2629 if (touchEvent.type() == QEvent::None)
2632 if (item->acceptTouchEvents()) {
2633 qCDebug(lcTouch) <<
"considering delivering" << &touchEvent <<
" to " << item;
2636 qCDebug(lcTouch) <<
"actually delivering" << &touchEvent <<
" to " << item;
2637 QCoreApplication::sendEvent(item, &touchEvent);
2638 eventAccepted = touchEvent.isAccepted();
2641 if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2642 !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
2643 deliverTouchAsMouse(item, &touchEvent);
2647 Q_ASSERT(item->acceptTouchEvents());
2648 if (eventAccepted) {
2649 bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
2650 for (
int i = 0; i < touchEvent.pointCount(); ++i) {
2651 auto &point = touchEvent.point(i);
2653 point.setAccepted();
2655 if (isPressOrRelease && !(itemPrivate->deliveryAgent() && pointerEvent->exclusiveGrabber(point)))
2656 pointerEvent->setExclusiveGrabber(point, item);
2661 for (
const auto &point: touchEvent.points()) {
2662 if (point.state() == QEventPoint::State::Pressed) {
2663 if (pointerEvent->exclusiveGrabber(point) == item) {
2664 qCDebug(lcTouchTarget) <<
"TP" << Qt::hex << point.id() <<
"disassociated";
2665 pointerEvent->setExclusiveGrabber(point,
nullptr);
2672#if QT_CONFIG(quick_draganddrop)
2673void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
2675 QObject *formerTarget = grabber->target();
2676 grabber->resetTarget();
2677 QQuickDragGrabber::iterator grabItem = grabber->begin();
2678 if (grabItem != grabber->end()) {
2679 Q_ASSERT(event->type() != QEvent::DragEnter);
2680 if (event->type() == QEvent::Drop) {
2681 QDropEvent *e =
static_cast<QDropEvent *>(event);
2682 for (e->setAccepted(
false); !e->isAccepted() && grabItem != grabber->end(); grabItem = grabber->release(grabItem)) {
2683 QPointF p = (**grabItem)->mapFromScene(e->position().toPoint());
2684 QDropEvent translatedEvent(
2686 e->possibleActions(),
2690 QQuickDropEventEx::copyActions(&translatedEvent, *e);
2691 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2692 e->setAccepted(translatedEvent.isAccepted());
2693 e->setDropAction(translatedEvent.dropAction());
2694 grabber->setTarget(**grabItem);
2697 if (event->type() != QEvent::DragMove) {
2698 QDragLeaveEvent leaveEvent;
2699 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2700 QCoreApplication::sendEvent(**grabItem, &leaveEvent);
2701 grabber->ignoreList().clear();
2704 QDragMoveEvent *moveEvent =
static_cast<QDragMoveEvent *>(event);
2708 QVarLengthArray<QQuickItem*, 64> currentGrabItems;
2709 for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
2710 currentGrabItems.append(**grabItem);
2713 QDragEnterEvent enterEvent(
2714 moveEvent->position(),
2715 moveEvent->possibleActions(),
2716 moveEvent->mimeData(),
2717 moveEvent->buttons(),
2718 moveEvent->modifiers());
2719 QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
2720 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, ¤tGrabItems,
2723 for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
2724 int i = currentGrabItems.indexOf(**grabItem);
2726 currentGrabItems.remove(i);
2728 QDragMoveEvent translatedEvent(
2729 (**grabItem)->mapFromScene(moveEvent->position()),
2730 moveEvent->possibleActions(),
2731 moveEvent->mimeData(),
2732 moveEvent->buttons(),
2733 moveEvent->modifiers());
2734 QQuickDropEventEx::copyActions(&translatedEvent, *moveEvent);
2735 QCoreApplication::sendEvent(**grabItem, &translatedEvent);
2736 event->setAccepted(translatedEvent.isAccepted());
2737 QQuickDropEventEx::copyActions(moveEvent, translatedEvent);
2742 QDragLeaveEvent leaveEvent;
2743 for (QQuickItem *i : currentGrabItems)
2744 QCoreApplication::sendEvent(i, &leaveEvent);
2749 if (event->type() == QEvent::DragEnter || event->type() == QEvent::DragMove) {
2750 QDragMoveEvent *e =
static_cast<QDragMoveEvent *>(event);
2751 QDragEnterEvent enterEvent(
2753 e->possibleActions(),
2757 QQuickDropEventEx::copyActions(&enterEvent, *e);
2758 event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
2760 grabber->ignoreList().clear();
2764bool QQuickDeliveryAgentPrivate::deliverDragEvent(
2765 QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
2766 QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
2768 QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
2769 if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
2771 QPointF p = item->mapFromScene(event->position().toPoint());
2772 bool itemContained = item->contains(p);
2774 const int itemIndex = grabber->ignoreList().indexOf(item);
2775 if (!itemContained) {
2777 grabber->ignoreList().remove(itemIndex);
2779 if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
2783 QDragEnterEvent enterEvent(
2785 event->possibleActions(),
2788 event->modifiers());
2789 QQuickDropEventEx::copyActions(&enterEvent, *event);
2790 QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
2793 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2794 if (children.at(ii)->z() < 0)
2796 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2800 if (itemContained) {
2803 if (currentGrabItems && currentGrabItems->contains(item)) {
2804 grabber->grab(item);
2805 grabber->setTarget(item);
2809 if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
2810 if (event->type() == QEvent::DragEnter) {
2812 QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
2813 if (formerTargetItem && currentGrabItems) {
2814 QDragLeaveEvent leaveEvent;
2815 QCoreApplication::sendEvent(formerTarget, &leaveEvent);
2819 currentGrabItems->removeAll(formerTarget);
2821 }
else if (itemIndex >= 0) {
2826 QDragMoveEvent translatedEvent(p, event->possibleActions(), event->mimeData(),
2827 event->buttons(), event->modifiers(), event->type());
2828 QQuickDropEventEx::copyActions(&translatedEvent, *event);
2829 translatedEvent.setAccepted(event->isAccepted());
2830 QCoreApplication::sendEvent(item, &translatedEvent);
2831 event->setAccepted(translatedEvent.isAccepted());
2832 event->setDropAction(translatedEvent.dropAction());
2833 if (event->type() == QEvent::DragEnter) {
2834 if (translatedEvent.isAccepted()) {
2835 grabber->grab(item);
2836 grabber->setTarget(item);
2838 }
else if (itemIndex < 0) {
2839 grabber->ignoreList().append(item);
2848 for (
int ii = children.size() - 1; ii >= 0; --ii) {
2849 if (children.at(ii)->z() >= 0)
2851 if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
2860
2861
2862
2863
2864
2865
2866
2867bool QQuickDeliveryAgentPrivate::sendFilteredPointerEvent(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2869 return sendFilteredPointerEventImpl(event, receiver, filteringParent ? filteringParent : receiver->parentItem());
2873
2874
2875bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
2877 if (!allowChildEventFiltering)
2879 if (!filteringParent)
2881 bool filtered =
false;
2882 const bool hasHandlers = QQuickItemPrivate::get(receiver)->hasPointerHandlers();
2883 if (filteringParent->filtersChildMouseEvents() && !hasFiltered.contains(filteringParent)) {
2884 hasFiltered.append(filteringParent);
2885 if (isMouseEvent(event)) {
2886 if (receiver->acceptedMouseButtons()) {
2887 const bool wasAccepted = event->allPointsAccepted();
2888 Q_ASSERT(event->pointCount());
2889 localizePointerEvent(event, receiver);
2890 event->setAccepted(
true);
2891 auto oldMouseGrabber = event->exclusiveGrabber(event->point(0));
2892 if (filteringParent->childMouseEventFilter(receiver, event)) {
2893 qCDebug(lcMouse) <<
"mouse event intercepted by childMouseEventFilter of " << filteringParent;
2894 skipDelivery.append(filteringParent);
2896 if (event->isAccepted() && event->isBeginEvent()) {
2897 auto &point = event->point(0);
2898 auto mouseGrabber = event->exclusiveGrabber(point);
2899 if (mouseGrabber && mouseGrabber != receiver && mouseGrabber != oldMouseGrabber) {
2900 receiver->mouseUngrabEvent();
2902 event->setExclusiveGrabber(point, receiver);
2907 event->setAccepted(wasAccepted);
2910 }
else if (isTouchEvent(event)) {
2911 const bool acceptsTouchEvents = receiver->acceptTouchEvents() || hasHandlers;
2912 auto device = event->device();
2913 if (device->type() == QInputDevice::DeviceType::TouchPad &&
2914 device->capabilities().testFlag(QInputDevice::Capability::MouseEmulation)) {
2915 qCDebug(lcTouchTarget) <<
"skipping filtering of synth-mouse event from" << device;
2916 }
else if (acceptsTouchEvents || receiver->acceptedMouseButtons()) {
2919 QMutableTouchEvent filteringParentTouchEvent;
2920 QQuickItemPrivate::get(receiver)->localizedTouchEvent(
static_cast<QTouchEvent *>(event),
true, &filteringParentTouchEvent);
2921 if (filteringParentTouchEvent.type() != QEvent::None) {
2922 qCDebug(lcTouch) <<
"letting parent" << filteringParent <<
"filter for" << receiver << &filteringParentTouchEvent;
2923 filtered = filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent);
2925 qCDebug(lcTouch) <<
"touch event intercepted by childMouseEventFilter of " << filteringParent;
2926 event->setAccepted(filteringParentTouchEvent.isAccepted());
2927 skipDelivery.append(filteringParent);
2928 if (event->isAccepted()) {
2929 for (
auto point : filteringParentTouchEvent.points()) {
2930 const QQuickItem *exclusiveGrabber = qobject_cast<
const QQuickItem *>(event->exclusiveGrabber(point));
2940 const bool grabberInsideFilteringParent = exclusiveGrabber &&
2941 exclusiveGrabber->acceptTouchEvents() &&
2942 filteringParent->isAncestorOf(
const_cast<QQuickItem *>(exclusiveGrabber));
2943 if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab() || grabberInsideFilteringParent)
2944 event->setExclusiveGrabber(point, filteringParent);
2952 for (
int i = 0; i < event->pointCount(); ++i)
2953 event->point(i).setAccepted(
false);
2955 }
else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
2956 !filteringParent->acceptTouchEvents()) {
2957 qCDebug(lcTouch) <<
"touch event NOT intercepted by childMouseEventFilter of " << filteringParent
2958 <<
"; accepts touch?" << filteringParent->acceptTouchEvents()
2959 <<
"receiver accepts touch?" << acceptsTouchEvents
2960 <<
"so, letting parent filter a synth-mouse event";
2962 for (
auto &tp : filteringParentTouchEvent.points()) {
2964 switch (tp.state()) {
2965 case QEventPoint::State::Pressed:
2966 t = QEvent::MouseButtonPress;
2968 case QEventPoint::State::Released:
2969 t = QEvent::MouseButtonRelease;
2971 case QEventPoint::State::Stationary:
2974 t = QEvent::MouseMove;
2978 bool touchMouseUnset = (touchMouseId == -1);
2980 if (touchMouseUnset || touchMouseId == tp.id()) {
2983 QMutableSinglePointEvent mouseEvent;
2984 touchToMouseEvent(t, tp, &filteringParentTouchEvent, &mouseEvent);
2988 touchMouseId = tp.id();
2989 touchMouseDevice = event->pointingDevice();
2990 filtered = filteringParent->childMouseEventFilter(receiver, &mouseEvent);
2992 qCDebug(lcTouch) <<
"touch event intercepted as synth mouse event by childMouseEventFilter of " << filteringParent;
2993 event->setAccepted(mouseEvent.isAccepted());
2994 skipDelivery.append(filteringParent);
2995 if (event->isAccepted() && event->isBeginEvent()) {
2996 qCDebug(lcTouchTarget) <<
"TP (mouse)" << Qt::hex << tp.id() <<
"->" << filteringParent;
2997 filteringParentTouchEvent.setExclusiveGrabber(tp, filteringParent);
2998 touchMouseUnset =
false;
2999 filteringParent->grabMouse();
3002 if (touchMouseUnset)
3005 cancelTouchMouseSynthesis();
3006 mouseEvent.point(0).setAccepted(
false);
3017 return sendFilteredPointerEventImpl(event, receiver, filteringParent->parentItem()) || filtered;
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031bool QQuickDeliveryAgentPrivate::sendFilteredMouseEvent(QEvent *event, QQuickItem *receiver, QQuickItem *filteringParent)
3033 if (!filteringParent)
3036 QQuickItemPrivate *filteringParentPrivate = QQuickItemPrivate::get(filteringParent);
3037 if (filteringParentPrivate->replayingPressEvent)
3040 bool filtered =
false;
3041 if (filteringParentPrivate->filtersChildMouseEvents && !hasFiltered.contains(filteringParent)) {
3042 hasFiltered.append(filteringParent);
3043 if (filteringParent->childMouseEventFilter(receiver, event)) {
3045 skipDelivery.append(filteringParent);
3047 qCDebug(lcMouseTarget) <<
"for" << receiver << filteringParent <<
"childMouseEventFilter ->" << filtered;
3050 return sendFilteredMouseEvent(event, receiver, filteringParent->parentItem()) || filtered;
3054
3055
3056
3057
3058
3059
3060bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event,
int startDragThreshold)
3062 QStyleHints *styleHints = QGuiApplication::styleHints();
3063 bool dragVelocityLimitAvailable = event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
3064 && styleHints->startDragVelocity();
3065 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3066 if (dragVelocityLimitAvailable) {
3067 QVector2D velocityVec = event->point(0).velocity();
3068 qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
3069 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3071 return overThreshold;
3075
3076
3077
3078
3079
3080
3081bool QQuickDeliveryAgentPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const QEventPoint &tp,
int startDragThreshold)
3083 QStyleHints *styleHints = qApp->styleHints();
3084 bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance());
3085 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
3086 if (!overThreshold && dragVelocityLimitAvailable) {
3087 qreal velocity = axis == Qt::XAxis ? tp.velocity().x() : tp.velocity().y();
3088 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
3090 return overThreshold;
3094
3095
3096
3097
3098bool QQuickDeliveryAgentPrivate::dragOverThreshold(QVector2D delta)
3100 int threshold = qApp->styleHints()->startDragDistance();
3101 return qAbs(delta.x()) > threshold || qAbs(delta.y()) > threshold;
3105
3106
3107
3108
3109
3110
3111QList<QQuickItem *> QQuickDeliveryAgentPrivate::contextMenuTargets(QQuickItem *item,
const QContextMenuEvent *event)
const
3113 auto predicate = [](QQuickItem *,
const QEvent *) -> std::optional<
bool> {
3114 return std::nullopt;
3117 const auto pos = event->pos().isNull() ? activeFocusItem->mapToScene({}).toPoint() : event->pos();
3118 if (event->pos().isNull())
3119 qCDebug(lcContextMenu) <<
"for QContextMenuEvent, active focus item is" << activeFocusItem <<
"@" << pos;
3120 return eventTargets(item, event, -1, pos, pos, predicate);
3124
3125
3126
3127
3128void QQuickDeliveryAgentPrivate::deliverContextMenuEvent(QContextMenuEvent *event)
3130 skipDelivery.clear();
3131 QList<QQuickItem *> targetItems = contextMenuTargets(rootItem, event);
3132 qCDebug(lcContextMenu) <<
"delivering context menu event" << event <<
"to" << targetItems.size() <<
"target item(s)";
3133 QList<QPointer<QQuickItem>> safeTargetItems(targetItems.begin(), targetItems.end());
3134 for (
auto &item : safeTargetItems) {
3135 qCDebug(lcContextMenu) <<
"- attempting to deliver to" << item;
3139 if (isSubsceneAgent)
3140 QQuickItemPrivate::get(item)->maybeHasSubsceneDeliveryAgent =
true;
3142 QCoreApplication::sendEvent(item, event);
3143 if (event->isAccepted())
3148#ifndef QT_NO_DEBUG_STREAM
3151 QDebugStateSaver saver(debug);
3154 debug <<
"QQuickDeliveryAgent(0)";
3158 debug <<
"QQuickDeliveryAgent(";
3159 if (!da->objectName().isEmpty())
3160 debug << da->objectName() <<
' ';
3161 auto root = da->rootItem();
3162 if (Q_LIKELY(root)) {
3163 debug <<
"root=" << root->metaObject()->className();
3164 if (!root->objectName().isEmpty())
3165 debug <<
' ' << root->objectName();
3176#include "moc_qquickdeliveryagent_p.cpp"
QDebug operator<<(QDebug dbg, const NSObject *nsObject)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static QQuickDeliveryAgentPrivate::HoverItems::iterator findHoverStateByItem(QQuickDeliveryAgentPrivate::HoverItems &hoverItems, QQuickItem *item)
static QQuickDeliveryAgentPrivate::HoverItems::const_iterator findHoverStateByItem(const QQuickDeliveryAgentPrivate::HoverItems &hoverItems, const QQuickItem *item)
static bool allowSyntheticRightClick()
static bool windowHasFocus(QQuickWindow *win)
static QQuickItem * findFurthestFocusScopeAncestor(QQuickItem *item)
Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text=QString(), bool autorep=false, ushort count=1)