File indexing completed on 2024-11-10 04:57:30
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"