File indexing completed on 2024-05-19 16:35:24

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