File indexing completed on 2024-04-28 05:30:14

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/surface.h"
0010 
0011 namespace KWin
0012 {
0013 
0014 CursorSource::CursorSource(QObject *parent)
0015     : QObject(parent)
0016 {
0017 }
0018 
0019 QSizeF CursorSource::size() const
0020 {
0021     return m_size;
0022 }
0023 
0024 QPointF CursorSource::hotspot() const
0025 {
0026     return m_hotspot;
0027 }
0028 
0029 ShapeCursorSource::ShapeCursorSource(QObject *parent)
0030     : CursorSource(parent)
0031 {
0032     m_delayTimer.setSingleShot(true);
0033     connect(&m_delayTimer, &QTimer::timeout, this, &ShapeCursorSource::selectNextSprite);
0034 }
0035 
0036 QImage ShapeCursorSource::image() const
0037 {
0038     return m_image;
0039 }
0040 
0041 QByteArray ShapeCursorSource::shape() const
0042 {
0043     return m_shape;
0044 }
0045 
0046 void ShapeCursorSource::setShape(const QByteArray &shape)
0047 {
0048     if (m_shape != shape) {
0049         m_shape = shape;
0050         refresh();
0051     }
0052 }
0053 
0054 void ShapeCursorSource::setShape(Qt::CursorShape shape)
0055 {
0056     setShape(CursorShape(shape).name());
0057 }
0058 
0059 KXcursorTheme ShapeCursorSource::theme() const
0060 {
0061     return m_theme;
0062 }
0063 
0064 void ShapeCursorSource::setTheme(const KXcursorTheme &theme)
0065 {
0066     if (m_theme != theme) {
0067         m_theme = theme;
0068         refresh();
0069     }
0070 }
0071 
0072 void ShapeCursorSource::refresh()
0073 {
0074     m_currentSprite = -1;
0075     m_delayTimer.stop();
0076 
0077     m_sprites = m_theme.shape(m_shape);
0078     if (m_sprites.isEmpty()) {
0079         const auto alternativeNames = CursorShape::alternatives(m_shape);
0080         for (const QByteArray &alternativeName : alternativeNames) {
0081             m_sprites = m_theme.shape(alternativeName);
0082             if (!m_sprites.isEmpty()) {
0083                 break;
0084             }
0085         }
0086     }
0087 
0088     if (!m_sprites.isEmpty()) {
0089         selectSprite(0);
0090     }
0091 }
0092 
0093 void ShapeCursorSource::selectNextSprite()
0094 {
0095     selectSprite((m_currentSprite + 1) % m_sprites.size());
0096 }
0097 
0098 void ShapeCursorSource::selectSprite(int index)
0099 {
0100     if (m_currentSprite == index) {
0101         return;
0102     }
0103     const KXcursorSprite &sprite = m_sprites[index];
0104     m_currentSprite = index;
0105     m_image = sprite.data();
0106     m_size = QSizeF(m_image.size()) / m_image.devicePixelRatio();
0107     m_hotspot = sprite.hotspot();
0108     if (sprite.delay().count() && m_sprites.size() > 1) {
0109         m_delayTimer.start(sprite.delay());
0110     }
0111     Q_EMIT changed();
0112 }
0113 
0114 SurfaceCursorSource::SurfaceCursorSource(QObject *parent)
0115     : CursorSource(parent)
0116 {
0117 }
0118 
0119 SurfaceInterface *SurfaceCursorSource::surface() const
0120 {
0121     return m_surface;
0122 }
0123 
0124 void SurfaceCursorSource::refresh()
0125 {
0126     m_size = m_surface->size();
0127     m_hotspot -= m_surface->offset();
0128     Q_EMIT changed();
0129 }
0130 
0131 void SurfaceCursorSource::reset()
0132 {
0133     m_size = QSizeF(0, 0);
0134     m_hotspot = QPointF(0, 0);
0135     m_surface = nullptr;
0136     Q_EMIT changed();
0137 }
0138 
0139 void SurfaceCursorSource::update(SurfaceInterface *surface, const QPointF &hotspot)
0140 {
0141     bool dirty = false;
0142 
0143     if (m_hotspot != hotspot) {
0144         dirty = true;
0145         m_hotspot = hotspot;
0146     }
0147 
0148     if (m_surface != surface) {
0149         dirty = true;
0150 
0151         if (m_surface) {
0152             disconnect(m_surface, &SurfaceInterface::committed, this, &SurfaceCursorSource::refresh);
0153             disconnect(m_surface, &SurfaceInterface::destroyed, this, &SurfaceCursorSource::reset);
0154         }
0155 
0156         m_surface = surface;
0157 
0158         if (m_surface) {
0159             m_size = surface->size();
0160 
0161             connect(m_surface, &SurfaceInterface::committed, this, &SurfaceCursorSource::refresh);
0162             connect(m_surface, &SurfaceInterface::destroyed, this, &SurfaceCursorSource::reset);
0163         } else {
0164             m_size = QSizeF(0, 0);
0165         }
0166     }
0167 
0168     if (dirty) {
0169         Q_EMIT changed();
0170     }
0171 }
0172 
0173 } // namespace KWin
0174 
0175 #include "moc_cursorsource.cpp"