File indexing completed on 2024-05-19 05:32:39

0001 /*
0002     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
0003     SPDX-FileCopyrightText: 2020 Adrien Faveraux <ad1rie3@hotmail.fr>
0004     SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "pointer.h"
0010 #include "clientconnection.h"
0011 #include "display.h"
0012 #include "pointer_p.h"
0013 #include "pointergestures_v1_p.h"
0014 #include "relativepointer_v1_p.h"
0015 #include "seat.h"
0016 #include "surface.h"
0017 #include "utils/common.h"
0018 #include "utils/resource.h"
0019 
0020 namespace KWin
0021 {
0022 class PointerSurfaceCursorPrivate
0023 {
0024 public:
0025     QPointF hotspot;
0026     QPointer<SurfaceInterface> surface;
0027 };
0028 
0029 PointerInterfacePrivate *PointerInterfacePrivate::get(PointerInterface *pointer)
0030 {
0031     return pointer->d.get();
0032 }
0033 
0034 PointerInterfacePrivate::PointerInterfacePrivate(PointerInterface *q, SeatInterface *seat)
0035     : q(q)
0036     , seat(seat)
0037     , relativePointersV1(new RelativePointerV1Interface(q))
0038     , swipeGesturesV1(new PointerSwipeGestureV1Interface(q))
0039     , pinchGesturesV1(new PointerPinchGestureV1Interface(q))
0040     , holdGesturesV1(new PointerHoldGestureV1Interface(q))
0041 {
0042 }
0043 
0044 PointerInterfacePrivate::~PointerInterfacePrivate()
0045 {
0046 }
0047 
0048 QList<PointerInterfacePrivate::Resource *> PointerInterfacePrivate::pointersForClient(ClientConnection *client) const
0049 {
0050     return resourceMap().values(client->client());
0051 }
0052 
0053 void PointerInterfacePrivate::pointer_set_cursor(Resource *resource, uint32_t serial, ::wl_resource *surface_resource, int32_t hotspot_x, int32_t hotspot_y)
0054 {
0055     SurfaceInterface *surface = nullptr;
0056 
0057     if (!focusedSurface) {
0058         return;
0059     }
0060     if (focusedSurface->client()->client() != resource->client()) {
0061         qCDebug(KWIN_CORE, "Denied set_cursor request from unfocused client");
0062         return;
0063     }
0064     if (focusedSerial != serial) {
0065         return;
0066     }
0067 
0068     if (surface_resource) {
0069         surface = SurfaceInterface::get(surface_resource);
0070         if (!surface) {
0071             wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid surface");
0072             return;
0073         }
0074 
0075         static SurfaceRole cursorRole(QByteArrayLiteral("cursor"));
0076         if (const SurfaceRole *role = surface->role()) {
0077             if (role != &cursorRole) {
0078                 wl_resource_post_error(resource->handle, error_role, "the wl_surface already has a role assigned %s", role->name().constData());
0079                 return;
0080             }
0081         } else {
0082             surface->setRole(&cursorRole);
0083         }
0084     }
0085 
0086     if (!cursor) {
0087         cursor = std::make_unique<PointerSurfaceCursor>();
0088     }
0089     cursor->d->hotspot = QPointF(hotspot_x, hotspot_y) / focusedSurface->client()->scaleOverride();
0090     cursor->d->surface = surface;
0091 
0092     Q_EMIT q->cursorChanged(cursor.get());
0093 }
0094 
0095 void PointerInterfacePrivate::pointer_release(Resource *resource)
0096 {
0097     wl_resource_destroy(resource->handle);
0098 }
0099 
0100 void PointerInterfacePrivate::pointer_bind_resource(Resource *resource)
0101 {
0102     const ClientConnection *focusedClient = focusedSurface ? focusedSurface->client() : nullptr;
0103 
0104     if (focusedClient && focusedClient->client() == resource->client()) {
0105         const quint32 serial = seat->display()->nextSerial();
0106         send_enter(resource->handle, serial, focusedSurface->resource(), wl_fixed_from_double(lastPosition.x()), wl_fixed_from_double(lastPosition.y()));
0107         if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) {
0108             send_frame(resource->handle);
0109         }
0110     }
0111 }
0112 
0113 void PointerInterfacePrivate::sendLeave(quint32 serial)
0114 {
0115     const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
0116     for (Resource *resource : pointerResources) {
0117         send_leave(resource->handle, serial, focusedSurface->resource());
0118     }
0119 }
0120 
0121 void PointerInterfacePrivate::sendEnter(const QPointF &position, quint32 serial)
0122 {
0123     const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
0124     for (Resource *resource : pointerResources) {
0125         send_enter(resource->handle, serial, focusedSurface->resource(), wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y()));
0126     }
0127 }
0128 
0129 void PointerInterfacePrivate::sendFrame()
0130 {
0131     const QList<Resource *> pointerResources = pointersForClient(focusedSurface->client());
0132     for (Resource *resource : pointerResources) {
0133         if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) {
0134             send_frame(resource->handle);
0135         }
0136     }
0137 }
0138 
0139 bool PointerInterfacePrivate::AxisAccumulator::Axis::shouldReset(int newDirection, std::chrono::milliseconds newTimestamp) const
0140 {
0141     if (newTimestamp.count() - timestamp.count() >= 1000) {
0142         return true;
0143     }
0144 
0145     // Reset the accumulator if the delta has opposite sign.
0146     return direction && ((direction < 0) != (newDirection < 0));
0147 }
0148 
0149 PointerInterface::PointerInterface(SeatInterface *seat)
0150     : d(new PointerInterfacePrivate(this, seat))
0151 {
0152 }
0153 
0154 PointerInterface::~PointerInterface()
0155 {
0156 }
0157 
0158 SurfaceInterface *PointerInterface::focusedSurface() const
0159 {
0160     return d->focusedSurface;
0161 }
0162 
0163 quint32 PointerInterface::focusedSerial() const
0164 {
0165     return d->focusedSerial;
0166 }
0167 
0168 void PointerInterface::sendEnter(SurfaceInterface *surface, const QPointF &position, quint32 serial)
0169 {
0170     if (d->focusedSurface == surface) {
0171         return;
0172     }
0173 
0174     if (d->focusedSurface) {
0175         d->sendLeave(serial);
0176         if (d->focusedSurface->client() != surface->client()) {
0177             d->sendFrame();
0178         }
0179         disconnect(d->destroyConnection);
0180     }
0181 
0182     d->focusedSurface = surface;
0183     d->focusedSerial = serial;
0184     d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this]() {
0185         d->sendLeave(d->seat->display()->nextSerial());
0186         d->sendFrame();
0187         d->focusedSurface = nullptr;
0188         Q_EMIT focusedSurfaceChanged();
0189     });
0190 
0191     d->sendEnter(d->focusedSurface->toSurfaceLocal(position), serial);
0192     d->sendFrame();
0193     d->lastPosition = position;
0194 
0195     Q_EMIT focusedSurfaceChanged();
0196 }
0197 
0198 void PointerInterface::sendLeave(quint32 serial)
0199 {
0200     if (!d->focusedSurface) {
0201         return;
0202     }
0203 
0204     d->sendLeave(serial);
0205     d->sendFrame();
0206 
0207     d->focusedSurface = nullptr;
0208     disconnect(d->destroyConnection);
0209 
0210     Q_EMIT focusedSurfaceChanged();
0211 }
0212 
0213 void PointerInterface::sendButton(quint32 button, PointerButtonState state, quint32 serial)
0214 {
0215     if (!d->focusedSurface) {
0216         return;
0217     }
0218 
0219     const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
0220     for (PointerInterfacePrivate::Resource *resource : pointerResources) {
0221         d->send_button(resource->handle, serial, d->seat->timestamp().count(), button, quint32(state));
0222     }
0223 }
0224 
0225 static void updateAccumulators(Qt::Orientation orientation, qreal delta, qint32 deltaV120, PointerInterfacePrivate *d, qint32 &valueAxisLowRes, qint32 &valueDiscrete)
0226 {
0227     const int newDirection = deltaV120 > 0 ? 1 : -1;
0228     auto &accum = d->axisAccumulator.axis(orientation);
0229 
0230     if (accum.shouldReset(newDirection, d->seat->timestamp())) {
0231         accum.reset();
0232     }
0233 
0234     accum.timestamp = d->seat->timestamp();
0235     accum.direction = newDirection;
0236 
0237     accum.axis += delta;
0238     accum.axis120 += deltaV120;
0239 
0240     // ±120 is a "wheel click"
0241     if (std::abs(accum.axis120) >= 60) {
0242         const int steps = accum.axis120 / 120;
0243         valueDiscrete += steps;
0244         if (steps == 0) {
0245             valueDiscrete += accum.direction;
0246         }
0247 
0248         accum.axis120 -= valueDiscrete * 120;
0249     }
0250 
0251     if (valueDiscrete) {
0252         // Accumulate the axis values to send to low-res clients
0253         valueAxisLowRes = accum.axis;
0254         accum.axis = 0;
0255     }
0256 }
0257 
0258 void PointerInterface::sendAxis(Qt::Orientation orientation, qreal delta, qint32 deltaV120, PointerAxisSource source, PointerAxisRelativeDirection direction)
0259 {
0260     if (!d->focusedSurface) {
0261         return;
0262     }
0263 
0264     qint32 valueAxisLowRes = 0;
0265     qint32 valueDiscrete = 0;
0266 
0267     if (deltaV120) {
0268         updateAccumulators(orientation, delta, deltaV120, d.get(),
0269                            valueAxisLowRes, valueDiscrete);
0270     } else {
0271         valueAxisLowRes = delta;
0272     }
0273 
0274     const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
0275     for (PointerInterfacePrivate::Resource *resource : pointerResources) {
0276         const quint32 version = resource->version();
0277 
0278         // Don't send anything if the client doesn't support high-res scrolling and
0279         // we haven't accumulated a wheel click's worth of events.
0280         if (version < WL_POINTER_AXIS_VALUE120_SINCE_VERSION && deltaV120 && !valueDiscrete) {
0281             continue;
0282         }
0283 
0284         if (source != PointerAxisSource::Unknown && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
0285             PointerInterfacePrivate::axis_source wlSource;
0286             switch (source) {
0287             case PointerAxisSource::Wheel:
0288                 wlSource = PointerInterfacePrivate::axis_source_wheel;
0289                 break;
0290             case PointerAxisSource::Finger:
0291                 wlSource = PointerInterfacePrivate::axis_source_finger;
0292                 break;
0293             case PointerAxisSource::Continuous:
0294                 wlSource = PointerInterfacePrivate::axis_source_continuous;
0295                 break;
0296             case PointerAxisSource::WheelTilt:
0297                 wlSource = PointerInterfacePrivate::axis_source_wheel_tilt;
0298                 break;
0299             default:
0300                 Q_UNREACHABLE();
0301                 break;
0302             }
0303             d->send_axis_source(resource->handle, wlSource);
0304         }
0305 
0306         const auto wlOrientation =
0307             (orientation == Qt::Vertical) ? PointerInterfacePrivate::axis_vertical_scroll : PointerInterfacePrivate::axis_horizontal_scroll;
0308 
0309         if (delta) {
0310             if (version >= WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION) {
0311                 auto wlRelativeDirection = direction == PointerAxisRelativeDirection::Normal ? PointerInterfacePrivate::axis_relative_direction_identical : PointerInterfacePrivate::axis_relative_direction_inverted;
0312 
0313                 d->send_axis_relative_direction(resource->handle, wlOrientation, wlRelativeDirection);
0314             }
0315             if (deltaV120) {
0316                 if (version >= WL_POINTER_AXIS_VALUE120_SINCE_VERSION) {
0317                     // Send high resolution scroll events if client supports them
0318                     d->send_axis_value120(resource->handle, wlOrientation, deltaV120);
0319                     d->send_axis(resource->handle, d->seat->timestamp().count(), wlOrientation,
0320                                  wl_fixed_from_double(delta));
0321                 } else {
0322                     if (version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION && valueDiscrete) {
0323                         // Send discrete scroll events if client supports them.
0324                         d->send_axis_discrete(resource->handle, wlOrientation,
0325                                               valueDiscrete);
0326                     }
0327                     // Send accumulated axis values
0328                     d->send_axis(resource->handle, d->seat->timestamp().count(), wlOrientation,
0329                                  wl_fixed_from_double(valueAxisLowRes));
0330                 }
0331             } else {
0332                 // Finger or continuous scroll
0333                 d->send_axis(resource->handle, d->seat->timestamp().count(), wlOrientation,
0334                              wl_fixed_from_double(delta));
0335             }
0336         } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
0337             d->send_axis_stop(resource->handle, d->seat->timestamp().count(), wlOrientation);
0338         }
0339     }
0340 }
0341 
0342 void PointerInterface::sendMotion(const QPointF &position)
0343 {
0344     d->lastPosition = position;
0345 
0346     if (!d->focusedSurface) {
0347         return;
0348     }
0349 
0350     const QPointF localPos = d->focusedSurface->toSurfaceLocal(position);
0351 
0352     const auto pointerResources = d->pointersForClient(d->focusedSurface->client());
0353     for (PointerInterfacePrivate::Resource *resource : pointerResources) {
0354         d->send_motion(resource->handle, d->seat->timestamp().count(), wl_fixed_from_double(localPos.x()), wl_fixed_from_double(localPos.y()));
0355     }
0356 }
0357 
0358 void PointerInterface::sendFrame()
0359 {
0360     if (d->focusedSurface) {
0361         d->sendFrame();
0362     }
0363 }
0364 
0365 SeatInterface *PointerInterface::seat() const
0366 {
0367     return d->seat;
0368 }
0369 
0370 PointerInterface *PointerInterface::get(wl_resource *native)
0371 {
0372     if (PointerInterfacePrivate *pointerPrivate = resource_cast<PointerInterfacePrivate *>(native)) {
0373         return pointerPrivate->q;
0374     }
0375     return nullptr;
0376 }
0377 
0378 PointerSurfaceCursor::PointerSurfaceCursor()
0379     : d(new PointerSurfaceCursorPrivate())
0380 {
0381 }
0382 
0383 PointerSurfaceCursor::~PointerSurfaceCursor()
0384 {
0385 }
0386 
0387 QPointF PointerSurfaceCursor::hotspot() const
0388 {
0389     return d->hotspot;
0390 }
0391 
0392 SurfaceInterface *PointerSurfaceCursor::surface() const
0393 {
0394     return d->surface;
0395 }
0396 
0397 } // namespace KWin
0398 
0399 #include "moc_pointer.cpp"