127void QQuickPointerHandler::setDragThreshold(
int t)
129 Q_D(QQuickPointerHandler);
130 if (d->dragThreshold == t)
133 if (t > std::numeric_limits<qint16>::max())
134 qWarning() <<
"drag threshold cannot exceed" << std::numeric_limits<qint16>::max();
135 d->dragThreshold = qint16(t);
136 emit dragThresholdChanged();
249void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition,
250 QPointerEvent *event, QEventPoint &point)
253 qCDebug(lcPointerHandlerGrab) << point << transition << grabber;
254 if (grabber ==
this) {
255 bool wasCanceled =
false;
256 switch (transition) {
257 case QPointingDevice::GrabPassive:
258 case QPointingDevice::GrabExclusive:
260 case QPointingDevice::CancelGrabPassive:
261 case QPointingDevice::CancelGrabExclusive:
264 case QPointingDevice::UngrabPassive:
265 case QPointingDevice::UngrabExclusive:
267 point.setAccepted(
false);
268 if (
auto par = parentItem()) {
269 Q_D(
const QQuickPointerHandler);
270 par->setKeepMouseGrab(d->hadKeepMouseGrab);
271 par->setKeepTouchGrab(d->hadKeepTouchGrab);
274 case QPointingDevice::OverrideGrabPassive:
280 emit canceled(point);
281 emit grabChanged(transition, point);
300void QQuickPointerHandler::setPassiveGrab(QPointerEvent *event,
const QEventPoint &point,
bool grab)
302 qCDebug(lcPointerHandlerGrab) <<
this << point << grab <<
"via"
303 << QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(parentItem());
305 event->addPassiveGrabber(point,
this);
307 event->removePassiveGrabber(point,
this);
322bool QQuickPointerHandler::canGrab(QPointerEvent *event,
const QEventPoint &point)
324 QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point));
325 return approveGrabTransition(event, point,
this) &&
326 (existingPhGrabber ? existingPhGrabber->approveGrabTransition(event, point,
this) :
true);
335bool QQuickPointerHandler::approveGrabTransition(QPointerEvent *event,
const QEventPoint &point, QObject *proposedGrabber)
337 Q_D(
const QQuickPointerHandler);
338 bool allowed =
false;
339 QObject* existingGrabber = event->exclusiveGrabber(point);
340 if (proposedGrabber ==
this) {
341 allowed = (existingGrabber ==
nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
342 if (existingGrabber) {
343 if (QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point))) {
344 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
345 existingPhGrabber->metaObject()->className() != metaObject()->className())
347 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfSameType) &&
348 existingPhGrabber->metaObject()->className() == metaObject()->className())
350 }
else if ((d->grabPermissions & CanTakeOverFromItems)) {
352 QQuickItem * existingItemGrabber = qobject_cast<QQuickItem *>(event->exclusiveGrabber(point));
353 auto da = parentItem() ? QQuickItemPrivate::get(parentItem())->deliveryAgentPrivate()
354 : QQuickDeliveryAgentPrivate::currentEventDeliveryAgent ?
static_cast<QQuickDeliveryAgentPrivate *>(
355 QQuickDeliveryAgentPrivate::get(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent)) :
nullptr;
356 const bool isTouchMouse = (da && da->isDeliveringTouchAsMouse());
357 if (existingItemGrabber &&
358 ((existingItemGrabber->keepMouseGrab() &&
359 (QQuickDeliveryAgentPrivate::isMouseEvent(event) || isTouchMouse)) ||
360 (existingItemGrabber->keepTouchGrab() && QQuickDeliveryAgentPrivate::isTouchEvent(event)))) {
369 if (existingItemGrabber->keepMouseGrab() &&
370 existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem())) {
372 if (isTouchMouse && point.id() == da->touchMouseId) {
373 qCDebug(lcPointerHandlerGrab) <<
this <<
"steals touchpoint" << point.id()
374 <<
"despite parent touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber;
379 qCDebug(lcPointerHandlerGrab) <<
this <<
"wants to grab point" << point.id()
380 <<
"but declines to steal from grabber" << existingItemGrabber
381 <<
"with keepMouseGrab=" << existingItemGrabber->keepMouseGrab()
382 <<
"keepTouchGrab=" << existingItemGrabber->keepTouchGrab();
389 if (proposedGrabber) {
390 if ((d->grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
392 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
393 proposedGrabber->metaObject()->className() != metaObject()->className())
395 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
396 proposedGrabber->metaObject()->className() == metaObject()->className())
398 if (!allowed && (d->grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits(
"QQuickItem"))
401 if (d->grabPermissions & ApprovesCancellation)
405 qCDebug(lcPointerHandlerGrab) <<
"point" << Qt::hex << point.id() <<
"permission" <<
406 QMetaEnum::fromType<GrabPermissions>().valueToKeys(grabPermissions()) <<
407 ':' <<
this << (allowed ?
"approved from" :
"denied from") <<
408 existingGrabber <<
"to" << proposedGrabber;
474void QQuickPointerHandler::componentComplete()
476 Q_D(
const QQuickPointerHandler);
477 if (
auto *parent = parentItem()) {
478 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
479 itemPriv->addPointerHandler(
this);
481 itemPriv->hasCursorHandler =
true;
482 itemPriv->setHasCursorInChild(
true);
507bool QQuickPointerHandler::setExclusiveGrab(QPointerEvent *ev,
const QEventPoint &point,
bool grab)
512 if ((grab && ev->exclusiveGrabber(point) ==
this) || (!grab && ev->exclusiveGrabber(point) !=
this))
517 allowed = canGrab(ev, point);
519 QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(ev->exclusiveGrabber(point));
521 if (existingPhGrabber && existingPhGrabber !=
this && !existingPhGrabber->approveGrabTransition(ev, point,
nullptr))
524 qCDebug(lcPointerHandlerGrab) << point << (grab ?
"grab" :
"ungrab") << (allowed ?
"allowed" :
"forbidden") <<
525 ev->exclusiveGrabber(point) <<
"->" << (grab ?
this :
nullptr);
527 ev->setExclusiveGrabber(point, grab ?
this :
nullptr);
534void QQuickPointerHandler::cancelAllGrabs(QPointerEvent *event, QEventPoint &point)
536 qCDebug(lcPointerHandlerGrab) << point;
537 if (event->exclusiveGrabber(point) ==
this) {
538 event->setExclusiveGrabber(point,
nullptr);
539 onGrabChanged(
this, QPointingDevice::CancelGrabExclusive, event, point);
541 if (event->removePassiveGrabber(point,
this))
542 onGrabChanged(
this, QPointingDevice::CancelGrabPassive, event, point);
569bool QQuickPointerHandler::parentContains(
const QPointF &scenePosition)
const
571 if (QQuickItem *par = parentItem()) {
573 QRectF windowGeometry = par->window()->geometry();
574 if (!par->window()->isTopLevel())
575 windowGeometry = QRectF(QWindowPrivate::get(par->window())->globalPosition(), par->window()->size());
576 QPointF screenPosition = par->window()->mapToGlobal(scenePosition);
577 if (!windowGeometry.contains(screenPosition))
580 QPointF p = par->mapFromScene(scenePosition);
583 return p.x() >= -m && p.y() >= -m && p.x() <= par->width() + m && p.y() <= par->height() + m;
584 return par->contains(p);
585 }
else if (parent() && parent()->inherits(
"QQuick3DModel")) {
675void QQuickPointerHandler::setParentItem(QQuickItem *p)
677 Q_D(QQuickPointerHandler);
678 if (QObject::parent() == p)
681 qCDebug(lcHandlerParent) <<
"reparenting handler" <<
this <<
":" << parent() <<
"->" << p;
682 auto *oldParent =
static_cast<QQuickItem *>(QObject::parent());
684 QQuickItemPrivate::get(oldParent)->removePointerHandler(
this);
687 QQuickItemPrivate::get(p)->addPointerHandler(
this);
688 d->onParentChanged(oldParent, p);
689 emit parentChanged();
719void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event)
721 Q_D(QQuickPointerHandler);
722 bool wants = wantsPointerEvent(event);
723 qCDebug(lcPointerHandlerDispatch) << metaObject()->className() << objectName()
724 <<
"on" << parent()->metaObject()->className() << parent()->objectName()
725 << (wants ?
"WANTS" :
"DECLINES") << event;
726 d->currentEvent = event;
728 handlePointerEventImpl(event);
729 d->lastEventTime = event->timestamp();
731#if QT_CONFIG(gestures)
732 if (event->type() != QEvent::NativeGesture)
735 for (
int i = 0; i < event->pointCount(); ++i) {
736 auto &pt = event->point(i);
737 if (event->exclusiveGrabber(pt) ==
this && pt.state() != QEventPoint::Stationary)
738 event->setExclusiveGrabber(pt,
nullptr);
741 d->currentEvent =
nullptr;
742 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->device()).append(
this);
795bool QQuickPointerHandler::wantsEventPoint(
const QPointerEvent *event,
const QEventPoint &point)
798 bool ret = event->exclusiveGrabber(point) ==
this ||
799 event->passiveGrabbers(point).contains(
this) || parentContains(point);
800 qCDebug(lcPointerHandlerDispatch) << Qt::hex << point.id() <<
"@" << point.scenePosition()
801 << metaObject()->className() << objectName() << ret;
886QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
887 : grabPermissions(QQuickPointerHandler::CanTakeOverFromItems |
888 QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType |
889 QQuickPointerHandler::ApprovesTakeOverByAnything)
890 , cursorShape(Qt::ArrowCursor)
893 , targetExplicitlySet(
false)
894 , hadKeepMouseGrab(
false)
895 , hadKeepTouchGrab(
false)
909bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const TEventPoint &p)
const
911 Q_Q(
const QQuickPointerHandler);
912 QStyleHints *styleHints = qApp->styleHints();
913 bool overThreshold = qAbs(d) > q->dragThreshold();
914 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
915 if (!overThreshold && dragVelocityLimitAvailable) {
916 qreal velocity = qreal(axis == Qt::XAxis ? p.velocity().x() : p.velocity().y());
917 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
919 return overThreshold;
942bool QQuickPointerHandlerPrivate::dragOverThreshold(
const QEventPoint &point)
const
944 QPointF delta = point.scenePosition() - point.scenePressPosition();
945 return (dragOverThreshold(delta.x(), Qt::XAxis, point) ||
946 dragOverThreshold(delta.y(), Qt::YAxis, point));