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