diff --git a/src/server/pointer_interface.cpp b/src/server/pointer_interface.cpp --- a/src/server/pointer_interface.cpp +++ b/src/server/pointer_interface.cpp @@ -241,7 +241,7 @@ return; } const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos()); - auto targetSurface = d->focusedSurface->surfaceAt(pos); + auto targetSurface = d->focusedSurface->inputSurfaceAt(pos); if (!targetSurface) { targetSurface = d->focusedSurface; } @@ -286,7 +286,7 @@ ); const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos()); - d->focusedChildSurface = QPointer(d->focusedSurface->surfaceAt(pos)); + d->focusedChildSurface = QPointer(d->focusedSurface->inputSurfaceAt(pos)); if (!d->focusedChildSurface) { d->focusedChildSurface = QPointer(d->focusedSurface); } diff --git a/src/server/surface_interface.h b/src/server/surface_interface.h --- a/src/server/surface_interface.h +++ b/src/server/surface_interface.h @@ -211,6 +211,21 @@ **/ SurfaceInterface *surfaceAt(const QPointF &position); + /** + * Finds the input receiving SurfaceInterface at the given @p position in surface-local coordinates. + * This can be either a descendant SurfaceInterface honoring the stacking order or + * the SurfaceInterface itself if its geometry contains the given @p position. + * + * If no such SurfaceInterface is found, e.g. because the SurfaceInterface is unmapped or there is no + * input region containing the position, + * @c nullptr is returned. + * + * @param position The position in surface-local coordinates + * @returns Input receiving child surface at the given @p position or surface itself at the position, might be @c nullptr + * @since 5.52 + **/ + SurfaceInterface *inputSurfaceAt(const QPointF &position); + /** * Sets the @p outputs this SurfaceInterface overlaps with, may be empty. * diff --git a/src/server/surface_interface.cpp b/src/server/surface_interface.cpp --- a/src/server/surface_interface.cpp +++ b/src/server/surface_interface.cpp @@ -860,6 +860,35 @@ return nullptr; } +SurfaceInterface *SurfaceInterface::inputSurfaceAt(const QPointF &position) +{ + // TODO: Most of this is very similar to SurfaceInterface::surfaceAt + // Is there a way to reduce the code duplication? + if (!isMapped()) { + return nullptr; + } + Q_D(); + // go from top to bottom. Top most child is last in list + QListIterator> it(d->current.children); + it.toBack(); + while (it.hasPrevious()) { + const auto ¤t = it.previous(); + auto surface = current->surface(); + if (surface.isNull()) { + continue; + } + if (auto s = surface->inputSurfaceAt(position - current->position())) { + return s; + } + } + // check whether the geometry and input region contain the pos + if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position) && + (inputIsInfinite() || input().contains(position.toPoint()))) { + return this; + } + return nullptr; +} + QPointer SurfaceInterface::lockedPointer() const { Q_D(); diff --git a/src/server/surface_interface_p.h b/src/server/surface_interface_p.h --- a/src/server/surface_interface_p.h +++ b/src/server/surface_interface_p.h @@ -81,6 +81,9 @@ void installPointerConstraint(ConfinedPointerInterface *confinement); void installIdleInhibitor(IdleInhibitorInterface *inhibitor); + typedef bool (*containsPtr) (const QSize &size, const QRegion &input, const QPointF &position); + SurfaceInterface *processAt(const QPointF &position, containsPtr contains); + void commitSubSurface(); void commit();