123void QQuickPointerHandler::setDragThreshold(
int t)
125 Q_D(QQuickPointerHandler);
126 if (d->dragThreshold == t)
129 if (t > std::numeric_limits<qint16>::max())
130 qWarning() <<
"drag threshold cannot exceed" << std::numeric_limits<qint16>::max();
131 d->dragThreshold = qint16(t);
132 emit dragThresholdChanged();
245void QQuickPointerHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition,
246 QPointerEvent *event, QEventPoint &point)
249 qCDebug(lcPointerHandlerGrab) << point << transition << grabber;
250 if (grabber ==
this) {
251 bool wasCanceled =
false;
252 switch (transition) {
253 case QPointingDevice::GrabPassive:
254 case QPointingDevice::GrabExclusive:
256 case QPointingDevice::CancelGrabPassive:
257 case QPointingDevice::CancelGrabExclusive:
260 case QPointingDevice::UngrabPassive:
261 case QPointingDevice::UngrabExclusive:
263 point.setAccepted(
false);
264 if (
auto par = parentItem()) {
265 Q_D(
const QQuickPointerHandler);
266 par->setKeepMouseGrab(d->hadKeepMouseGrab);
267 par->setKeepTouchGrab(d->hadKeepTouchGrab);
270 case QPointingDevice::OverrideGrabPassive:
276 emit canceled(point);
277 emit grabChanged(transition, point);
296void QQuickPointerHandler::setPassiveGrab(QPointerEvent *event,
const QEventPoint &point,
bool grab)
298 qCDebug(lcPointerHandlerGrab) <<
this << point << grab <<
"via"
299 << QQuickDeliveryAgentPrivate::currentOrItemDeliveryAgent(parentItem());
301 event->addPassiveGrabber(point,
this);
303 event->removePassiveGrabber(point,
this);
318bool QQuickPointerHandler::canGrab(QPointerEvent *event,
const QEventPoint &point)
320 QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point));
321 return approveGrabTransition(event, point,
this) &&
322 (existingPhGrabber ? existingPhGrabber->approveGrabTransition(event, point,
this) :
true);
331bool QQuickPointerHandler::approveGrabTransition(QPointerEvent *event,
const QEventPoint &point, QObject *proposedGrabber)
333 Q_D(
const QQuickPointerHandler);
334 bool allowed =
false;
335 QObject* existingGrabber = event->exclusiveGrabber(point);
336 if (proposedGrabber ==
this) {
337 allowed = (existingGrabber ==
nullptr) || ((d->grabPermissions & CanTakeOverFromAnything) == CanTakeOverFromAnything);
338 if (existingGrabber) {
339 if (QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(event->exclusiveGrabber(point))) {
340 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfDifferentType) &&
341 existingPhGrabber->metaObject()->className() != metaObject()->className())
343 if (!allowed && (d->grabPermissions & CanTakeOverFromHandlersOfSameType) &&
344 existingPhGrabber->metaObject()->className() == metaObject()->className())
346 }
else if ((d->grabPermissions & CanTakeOverFromItems)) {
348 QQuickItem * existingItemGrabber = qobject_cast<QQuickItem *>(event->exclusiveGrabber(point));
349 auto da = parentItem() ? QQuickItemPrivate::get(parentItem())->deliveryAgentPrivate()
350 : QQuickDeliveryAgentPrivate::currentEventDeliveryAgent ?
static_cast<QQuickDeliveryAgentPrivate *>(
351 QQuickDeliveryAgentPrivate::get(QQuickDeliveryAgentPrivate::currentEventDeliveryAgent)) :
nullptr;
352 const bool isTouchMouse = (da && da->isDeliveringTouchAsMouse());
353 if (existingItemGrabber &&
354 ((existingItemGrabber->keepMouseGrab() &&
355 (QQuickDeliveryAgentPrivate::isMouseEvent(event) || isTouchMouse)) ||
356 (existingItemGrabber->keepTouchGrab() && QQuickDeliveryAgentPrivate::isTouchEvent(event)))) {
365 if (existingItemGrabber->keepMouseGrab() &&
366 existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem())) {
368 if (isTouchMouse && point.id() == da->touchMouseId) {
369 qCDebug(lcPointerHandlerGrab) <<
this <<
"steals touchpoint" << point.id()
370 <<
"despite parent touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber;
375 qCDebug(lcPointerHandlerGrab) <<
this <<
"wants to grab point" << point.id()
376 <<
"but declines to steal from grabber" << existingItemGrabber
377 <<
"with keepMouseGrab=" << existingItemGrabber->keepMouseGrab()
378 <<
"keepTouchGrab=" << existingItemGrabber->keepTouchGrab();
385 if (proposedGrabber) {
386 if ((d->grabPermissions & ApprovesTakeOverByAnything) == ApprovesTakeOverByAnything)
388 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfDifferentType) &&
389 proposedGrabber->metaObject()->className() != metaObject()->className())
391 if (!allowed && (d->grabPermissions & ApprovesTakeOverByHandlersOfSameType) &&
392 proposedGrabber->metaObject()->className() == metaObject()->className())
394 if (!allowed && (d->grabPermissions & ApprovesTakeOverByItems) && proposedGrabber->inherits(
"QQuickItem"))
397 if (d->grabPermissions & ApprovesCancellation)
401 qCDebug(lcPointerHandlerGrab) <<
"point" << Qt::hex << point.id() <<
"permission" <<
402 QMetaEnum::fromType<GrabPermissions>().valueToKeys(grabPermissions()) <<
403 ':' <<
this << (allowed ?
"approved from" :
"denied from") <<
404 existingGrabber <<
"to" << proposedGrabber;
470void QQuickPointerHandler::componentComplete()
472 Q_D(
const QQuickPointerHandler);
473 if (
auto *parent = parentItem()) {
474 QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
475 itemPriv->addPointerHandler(
this);
477 itemPriv->hasCursorHandler =
true;
478 itemPriv->setHasCursorInChild(
true);
503bool QQuickPointerHandler::setExclusiveGrab(QPointerEvent *ev,
const QEventPoint &point,
bool grab)
508 if ((grab && ev->exclusiveGrabber(point) ==
this) || (!grab && ev->exclusiveGrabber(point) !=
this))
513 allowed = canGrab(ev, point);
515 QQuickPointerHandler *existingPhGrabber = qobject_cast<QQuickPointerHandler *>(ev->exclusiveGrabber(point));
517 if (existingPhGrabber && existingPhGrabber !=
this && !existingPhGrabber->approveGrabTransition(ev, point,
nullptr))
520 qCDebug(lcPointerHandlerGrab) << point << (grab ?
"grab" :
"ungrab") << (allowed ?
"allowed" :
"forbidden") <<
521 ev->exclusiveGrabber(point) <<
"->" << (grab ?
this :
nullptr);
523 ev->setExclusiveGrabber(point, grab ?
this :
nullptr);
530void QQuickPointerHandler::cancelAllGrabs(QPointerEvent *event, QEventPoint &point)
532 qCDebug(lcPointerHandlerGrab) << point;
533 if (event->exclusiveGrabber(point) ==
this) {
534 event->setExclusiveGrabber(point,
nullptr);
535 onGrabChanged(
this, QPointingDevice::CancelGrabExclusive, event, point);
537 if (event->removePassiveGrabber(point,
this))
538 onGrabChanged(
this, QPointingDevice::CancelGrabPassive, event, point);
565bool QQuickPointerHandler::parentContains(
const QPointF &scenePosition)
const
567 if (QQuickItem *par = parentItem()) {
569 QRectF windowGeometry = par->window()->geometry();
570 if (!par->window()->isTopLevel())
571 windowGeometry = QRectF(QWindowPrivate::get(par->window())->globalPosition(), par->window()->size());
572 QPointF screenPosition = par->window()->mapToGlobal(scenePosition);
573 if (!windowGeometry.contains(screenPosition))
576 QPointF p = par->mapFromScene(scenePosition);
579 return p.x() >= -m && p.y() >= -m && p.x() <= par->width() + m && p.y() <= par->height() + m;
580 return par->contains(p);
581 }
else if (parent() && parent()->inherits(
"QQuick3DModel")) {
671void QQuickPointerHandler::setParentItem(QQuickItem *p)
673 Q_D(QQuickPointerHandler);
674 if (QObject::parent() == p)
677 qCDebug(lcHandlerParent) <<
"reparenting handler" <<
this <<
":" << parent() <<
"->" << p;
678 auto *oldParent =
static_cast<QQuickItem *>(QObject::parent());
680 QQuickItemPrivate::get(oldParent)->removePointerHandler(
this);
683 QQuickItemPrivate::get(p)->addPointerHandler(
this);
684 d->onParentChanged(oldParent, p);
685 emit parentChanged();
715void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event)
717 Q_D(QQuickPointerHandler);
718 bool wants = wantsPointerEvent(event);
719 qCDebug(lcPointerHandlerDispatch) << metaObject()->className() << objectName()
720 <<
"on" << parent()->metaObject()->className() << parent()->objectName()
721 << (wants ?
"WANTS" :
"DECLINES") << event;
722 d->currentEvent = event;
724 handlePointerEventImpl(event);
725 d->lastEventTime = event->timestamp();
727#if QT_CONFIG(gestures)
728 if (event->type() != QEvent::NativeGesture)
731 for (
int i = 0; i < event->pointCount(); ++i) {
732 auto &pt = event->point(i);
733 if (event->exclusiveGrabber(pt) ==
this && pt.state() != QEventPoint::Stationary)
734 event->setExclusiveGrabber(pt,
nullptr);
737 d->currentEvent =
nullptr;
738 QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->device()).append(
this);
791bool QQuickPointerHandler::wantsEventPoint(
const QPointerEvent *event,
const QEventPoint &point)
794 bool ret = event->exclusiveGrabber(point) ==
this ||
795 event->passiveGrabbers(point).contains(
this) || parentContains(point);
796 qCDebug(lcPointerHandlerDispatch) << Qt::hex << point.id() <<
"@" << point.scenePosition()
797 << metaObject()->className() << objectName() << ret;
877QQuickPointerHandlerPrivate::QQuickPointerHandlerPrivate()
878 : grabPermissions(QQuickPointerHandler::CanTakeOverFromItems |
879 QQuickPointerHandler::CanTakeOverFromHandlersOfDifferentType |
880 QQuickPointerHandler::ApprovesTakeOverByAnything)
881 , cursorShape(Qt::ArrowCursor)
884 , targetExplicitlySet(
false)
885 , hadKeepMouseGrab(
false)
886 , hadKeepTouchGrab(
false)
900bool QQuickPointerHandlerPrivate::dragOverThreshold(qreal d, Qt::Axis axis,
const TEventPoint &p)
const
902 Q_Q(
const QQuickPointerHandler);
903 QStyleHints *styleHints = qApp->styleHints();
904 bool overThreshold = qAbs(d) > q->dragThreshold();
905 const bool dragVelocityLimitAvailable = (styleHints->startDragVelocity() > 0);
906 if (!overThreshold && dragVelocityLimitAvailable) {
907 qreal velocity = qreal(axis == Qt::XAxis ? p.velocity().x() : p.velocity().y());
908 overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
910 return overThreshold;
933bool QQuickPointerHandlerPrivate::dragOverThreshold(
const QEventPoint &point)
const
935 QPointF delta = point.scenePosition() - point.scenePressPosition();
936 return (dragOverThreshold(delta.x(), Qt::XAxis, point) ||
937 dragOverThreshold(delta.y(), Qt::YAxis, point));