Warning, file /plasma/kwin/src/cursorsource.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "cursorsource.h" 0008 #include "cursor.h" 0009 #include "wayland/clientconnection.h" 0010 #include "wayland/shmclientbuffer.h" 0011 #include "wayland/surface_interface.h" 0012 0013 namespace KWin 0014 { 0015 0016 CursorSource::CursorSource(QObject *parent) 0017 : QObject(parent) 0018 { 0019 } 0020 0021 QImage CursorSource::image() const 0022 { 0023 return m_image; 0024 } 0025 0026 QSize CursorSource::size() const 0027 { 0028 return m_size; 0029 } 0030 0031 QPoint CursorSource::hotspot() const 0032 { 0033 return m_hotspot; 0034 } 0035 0036 ImageCursorSource::ImageCursorSource(QObject *parent) 0037 : CursorSource(parent) 0038 { 0039 } 0040 0041 void ImageCursorSource::update(const QImage &image, const QPoint &hotspot) 0042 { 0043 m_image = image; 0044 m_size = image.size() / image.devicePixelRatio(); 0045 m_hotspot = hotspot; 0046 Q_EMIT changed(); 0047 } 0048 0049 ShapeCursorSource::ShapeCursorSource(QObject *parent) 0050 : CursorSource(parent) 0051 { 0052 m_delayTimer.setSingleShot(true); 0053 connect(&m_delayTimer, &QTimer::timeout, this, &ShapeCursorSource::selectNextSprite); 0054 } 0055 0056 QByteArray ShapeCursorSource::shape() const 0057 { 0058 return m_shape; 0059 } 0060 0061 void ShapeCursorSource::setShape(const QByteArray &shape) 0062 { 0063 if (m_shape != shape) { 0064 m_shape = shape; 0065 refresh(); 0066 } 0067 } 0068 0069 void ShapeCursorSource::setShape(Qt::CursorShape shape) 0070 { 0071 setShape(CursorShape(shape).name()); 0072 } 0073 0074 KXcursorTheme ShapeCursorSource::theme() const 0075 { 0076 return m_theme; 0077 } 0078 0079 void ShapeCursorSource::setTheme(const KXcursorTheme &theme) 0080 { 0081 if (m_theme != theme) { 0082 m_theme = theme; 0083 refresh(); 0084 } 0085 } 0086 0087 void ShapeCursorSource::refresh() 0088 { 0089 m_currentSprite = -1; 0090 m_delayTimer.stop(); 0091 0092 m_sprites = m_theme.shape(m_shape); 0093 if (m_sprites.isEmpty()) { 0094 const auto alternativeNames = Cursor::cursorAlternativeNames(m_shape); 0095 for (const QByteArray &alternativeName : alternativeNames) { 0096 m_sprites = m_theme.shape(alternativeName); 0097 if (!m_sprites.isEmpty()) { 0098 break; 0099 } 0100 } 0101 } 0102 0103 if (!m_sprites.isEmpty()) { 0104 selectSprite(0); 0105 } 0106 } 0107 0108 void ShapeCursorSource::selectNextSprite() 0109 { 0110 selectSprite((m_currentSprite + 1) % m_sprites.size()); 0111 } 0112 0113 void ShapeCursorSource::selectSprite(int index) 0114 { 0115 if (m_currentSprite == index) { 0116 return; 0117 } 0118 const KXcursorSprite &sprite = m_sprites[index]; 0119 m_currentSprite = index; 0120 m_image = sprite.data(); 0121 m_size = m_image.size() / m_image.devicePixelRatio(); 0122 m_hotspot = sprite.hotspot(); 0123 if (sprite.delay().count() && m_sprites.size() > 1) { 0124 m_delayTimer.start(sprite.delay()); 0125 } 0126 Q_EMIT changed(); 0127 } 0128 0129 SurfaceCursorSource::SurfaceCursorSource(QObject *parent) 0130 : CursorSource(parent) 0131 { 0132 } 0133 0134 KWaylandServer::SurfaceInterface *SurfaceCursorSource::surface() const 0135 { 0136 return m_surface; 0137 } 0138 0139 void SurfaceCursorSource::update(KWaylandServer::SurfaceInterface *surface, const QPoint &hotspot) 0140 { 0141 if (!surface) { 0142 m_image = QImage(); 0143 m_size = QSize(0, 0); 0144 m_hotspot = QPoint(); 0145 m_surface = nullptr; 0146 } else { 0147 // TODO Plasma 6: once Xwayland cursor scaling can be done correctly, remove this 0148 // scaling is intentionally applied "wrong" here to make the cursor stay a consistent size even with un-scaled Xwayland: 0149 // - the device pixel ratio of the image is not multiplied by scaleOverride 0150 // - the surface size is scaled up with scaleOverride, to un-do the scaling done elsewhere 0151 auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(surface->buffer()); 0152 if (buffer) { 0153 m_image = buffer->data().copy(); 0154 m_image.setDevicePixelRatio(surface->bufferScale()); 0155 } else { 0156 m_image = QImage(); 0157 } 0158 m_size = (surface->size() * surface->client()->scaleOverride()).toSize(); 0159 m_hotspot = hotspot; 0160 m_surface = surface; 0161 } 0162 Q_EMIT changed(); 0163 } 0164 0165 } // namespace KWin