98void QQuickPointerHandler::setMargin(qreal pointDistanceThreshold)
100 Q_D(QQuickPointerHandler);
101 if (d->m_margin == pointDistanceThreshold)
104 d->m_margin = pointDistanceThreshold;
105 if (
auto *parent = parentItem()) {
106 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
108 itemPriv->extra.value().biggestPointerHandlerMarginCache = -1;
110 emit marginChanged();
132void QQuickPointerHandler::setDragThreshold(
int t)
134 Q_D(QQuickPointerHandler);
135 if (d->dragThreshold == t)
138 if (t > std::numeric_limits<qint16>::max())
139 qWarning() <<
"drag threshold cannot exceed" << std::numeric_limits<qint16>::max();
140 d->dragThreshold = qint16(t);
141 emit dragThresholdChanged();
254void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition,
255 QPointerEvent *event, QEventPoint &point)
258 qCDebug(lcPointerHandlerGrab) << point << transition << grabber;
259 if (grabber ==
this) {
260 bool wasCanceled =
false;
261 switch (transition) {
262 case QPointingDevice::GrabPassive:
263 case QPointingDevice::GrabExclusive:
265 case QPointingDevice::CancelGrabPassive:
266 case QPointingDevice::CancelGrabExclusive:
269 case QPointingDevice::UngrabPassive:
270 case QPointingDevice::UngrabExclusive:
272 point.setAccepted(
false);
273 if (
auto par = parentItem()) {
274 Q_D(
const QQuickPointerHandler);
275 par->setKeepMouseGrab(d->hadKeepMouseGrab);
276 par->setKeepTouchGrab(d->hadKeepTouchGrab);
279 case QPointingDevice::OverrideGrabPassive:
285 emit canceled(point);
286 emit grabChanged(transition, point);
305void QQuickPointerHandler::setPassiveGrab(QPointerEvent *event,
const QEventPoint &point,
bool grab)
307 qCDebug(lcPointerHandlerGrab) <<
this << point << grab <<
"via"
308 << QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(parentItem());
310 event->addPassiveGrabber(point,
this);
312 event->removePassiveGrabber(point,
this);
327bool QQuickPointerHandler::canGrab(QPointerEvent *event,
const QEventPoint &point)
329 QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point));
330 return approveGrabTransition(event, point,
this) &&
331 (existingPhGrabber ? existingPhGrabber->approveGrabTransition(event, point,
this) :
true);
340bool QQuickPointerHandler::approveGrabTransition(QPointerEvent *event,
const QEventPoint &point, QObject *proposedGrabber)
342 Q_D(
const QQuickPointerHandler);
343 bool allowed =
false;
344 QObject* existingGrabber = event->exclusiveGrabber(point);
345 if (proposedGrabber ==
this) {
346 allowed = (existingGrabber ==
nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
347 if (existingGrabber) {
348 if (QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point))) {
349 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
350 existingPhGrabber->metaObject()->className() != metaObject()->className())
352 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfSameType) &&
353 existingPhGrabber->metaObject()->className() == metaObject()->className())
355 }
else if ((d->grabPermissions & CanTakeOverFromItems)) {
357 QQuickItem * existingItemGrabber = qobject_cast<QQuickItem *>(event->exclusiveGrabber(point));
358 auto da = parentItem() ? QQuickItemPrivate::get(parentItem())->deliveryAgentPrivate()
359 : QQuickDeliveryAgentPrivate::currentEventDeliveryAgent ?
static_cast<QQuickDeliveryAgentPrivate *>(
360 QQuickDeliveryAgentPrivate::get(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent)) :
nullptr;
361 const bool isTouchMouse = (da && da->isDeliveringTouchAsMouse());
362 if (existingItemGrabber &&
363 ((existingItemGrabber->keepMouseGrab() &&
364 (QQuickDeliveryAgentPrivate::isMouseEvent(event) || isTouchMouse)) ||
365 (existingItemGrabber->keepTouchGrab() && QQuickDeliveryAgentPrivate::isTouchEvent(event)))) {
374 if (existingItemGrabber->keepMouseGrab() &&
375 existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem())) {
377 if (isTouchMouse && point.id() == da->touchMouseId) {
378 qCDebug(lcPointerHandlerGrab) <<
this <<
"steals touchpoint" << point.id()
379 <<
"despite parent touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber;
384 qCDebug(lcPointerHandlerGrab) <<
this <<
"wants to grab point" << point.id()
385 <<
"but declines to steal from grabber" << existingItemGrabber
386 <<
"with keepMouseGrab=" << existingItemGrabber->keepMouseGrab()
387 <<
"keepTouchGrab=" << existingItemGrabber->keepTouchGrab();
394 if (proposedGrabber) {
395 if ((d->grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
397 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
398 proposedGrabber->metaObject()->className() != metaObject()->className())
400 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
401 proposedGrabber->metaObject()->className() == metaObject()->className())
403 if (!allowed && (d->grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits(
"QQuickItem"))
406 if (d->grabPermissions & ApprovesCancellation)
410 qCDebug(lcPointerHandlerGrab) <<
"point" << Qt::hex << point.id() <<
"permission" <<
411 QMetaEnum::fromType<GrabPermissions>().valueToKeys(grabPermissions()) <<
412 ':' <<
this << (allowed ?
"approved from" :
"denied from") <<
413 existingGrabber <<
"to" << proposedGrabber;
479void QQuickPointerHandler::componentComplete()
481 Q_D(
const QQuickPointerHandler);
482 if (
auto *parent = parentItem()) {
483 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
484 itemPriv->addPointerHandler(
this);
486 itemPriv->hasCursorHandler =
true;
487 itemPriv->setHasCursorInChild(
true);
512bool QQuickPointerHandler::setExclusiveGrab(QPointerEvent *ev,
const QEventPoint &point,
bool grab)
517 if ((grab && ev->exclusiveGrabber(point) ==
this) || (!grab && ev->exclusiveGrabber(point) !=
this))
522 allowed = canGrab(ev, point);
524 QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(ev->exclusiveGrabber(point));
526 if (existingPhGrabber && existingPhGrabber !=
this && !existingPhGrabber->approveGrabTransition(ev, point,
nullptr))
529 qCDebug(lcPointerHandlerGrab) << point << (grab ?
"grab" :
"ungrab") << (allowed ?
"allowed" :
"forbidden") <<
530 ev->exclusiveGrabber(point) <<
"->" << (grab ?
this :
nullptr);
532 ev->setExclusiveGrabber(point, grab ?
this :
nullptr);
539void QQuickPointerHandler::cancelAllGrabs(QPointerEvent *event, QEventPoint &point)
541 qCDebug(lcPointerHandlerGrab) << point;
542 if (event->exclusiveGrabber(point) ==
this) {
543 event->setExclusiveGrabber(point,
nullptr);
544 onGrabChanged(
this, QPointingDevice::CancelGrabExclusive, event, point);
546 if (event->removePassiveGrabber(point,
this))
547 onGrabChanged(
this, QPointingDevice::CancelGrabPassive, event, point);
574bool QQuickPointerHandler::parentContains(
const QPointF &localPosition,
const QPointF &scenePosition)
const
576 if (QQuickItem *par = parentItem()) {
578 QRectF windowGeometry = par->window()->geometry();
579 if (!par->window()->isTopLevel())
580 windowGeometry = QRectF(QWindowPrivate::get(par->window())->globalPosition(), par->window()->size());
581 QPointF screenPosition = par->window()->mapToGlobal(scenePosition);
582 if (!windowGeometry.contains(screenPosition))
587 return localPosition.x() >= -m && localPosition.y() >= -m &&
588 localPosition.x() <= par->width() + m && localPosition.y() <= par->height() + m;
589 return par->contains(localPosition);
590 }
else if (parent() && parent()->inherits(
"QQuick3DModel")) {
687void QQuickPointerHandler::setParentItem(QQuickItem *p)
689 Q_D(QQuickPointerHandler);
690 if (QObject::parent() == p)
693 qCDebug(lcHandlerParent) <<
"reparenting handler" <<
this <<
":" << parent() <<
"->" << p;
694 auto *oldParent =
static_cast<QQuickItem *>(QObject::parent());
696 QQuickItemPrivate::get(oldParent)->removePointerHandler(
this);
699 QQuickItemPrivate::get(p)->addPointerHandler(
this);
700 d->onParentChanged(oldParent, p);
701 emit parentChanged();
731void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event)
733 Q_D(QQuickPointerHandler);
734 bool wants = wantsPointerEvent(event);
735 qCDebug(lcPointerHandlerDispatch) << metaObject()->className() << objectName()
736 <<
"on" << parent()->metaObject()->className() << parent()->objectName()
737 << (wants ?
"WANTS" :
"DECLINES") << event;
738 d->currentEvent = event;
740 handlePointerEventImpl(event);
741 d->lastEventTime = event->timestamp();
743#if QT_CONFIG(gestures)
744 if (event->type() != QEvent::NativeGesture)
747 for (
int i = 0; i < event->pointCount(); ++i) {
748 auto &pt = event->point(i);
749 if (event->exclusiveGrabber(pt) ==
this && pt.state() != QEventPoint::Stationary)
750 event->setExclusiveGrabber(pt,
nullptr);
753 d->currentEvent =
nullptr;
754 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->device()).append(
this);
807bool QQuickPointerHandler::wantsEventPoint(
const QPointerEvent *event,
const QEventPoint &point)
810 bool ret = event->exclusiveGrabber(point) ==
this ||
811 event->passiveGrabbers(point).contains(
this) || parentContains(point);
812 qCDebug(lcPointerHandlerDispatch) << Qt::hex << point.id() <<
"@" << point.scenePosition()
813 << metaObject()->className() << objectName() << ret;
898QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
899 : grabPermissions(QQuickPointerHandler::CanTakeOverFromItems |
900 QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType |
901 QQuickPointerHandler::ApprovesTakeOverByAnything)
902 , cursorShape(Qt::ArrowCursor)
905 , targetExplicitlySet(
false)
906 , hadKeepMouseGrab(
false)
907 , hadKeepTouchGrab(
false)
921bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const TEventPoint &p)
const
923 Q_Q(
const QQuickPointerHandler);
924 QStyleHints *styleHints = qApp->styleHints();
925 bool overThreshold = qAbs(d) > q->dragThreshold();
926 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
927 if (!overThreshold && dragVelocityLimitAvailable) {
928 qreal velocity = qreal(axis == Qt::XAxis ? p.velocity().x() : p.velocity().y());
929 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
931 return overThreshold;
954bool QQuickPointerHandlerPrivate::dragOverThreshold(
const QEventPoint &point)
const
956 QPointF delta = point.scenePosition() - point.scenePressPosition();
957 return (dragOverThreshold(delta.x(), Qt::XAxis, point) ||
958 dragOverThreshold(delta.y(), Qt::YAxis, point));