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

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "cursor.h"
0011 // kwin
0012 #include "compositor.h"
0013 #include "core/output.h"
0014 #include "cursorsource.h"
0015 #include "input.h"
0016 #include "keyboard_input.h"
0017 #include "main.h"
0018 #include "scene/workspacescene.h"
0019 #include "utils/common.h"
0020 #include "utils/xcbutils.h"
0021 // KDE
0022 #include <KConfig>
0023 #include <KConfigGroup>
0024 // Qt
0025 #include <QAbstractEventDispatcher>
0026 #include <QDBusConnection>
0027 #include <QScreen>
0028 #include <QTimer>
0029 
0030 #include <xcb/xcb_cursor.h>
0031 
0032 namespace KWin
0033 {
0034 Cursors *Cursors::s_self = nullptr;
0035 Cursors *Cursors::self()
0036 {
0037     if (!s_self) {
0038         s_self = new Cursors;
0039     }
0040     return s_self;
0041 }
0042 
0043 void Cursors::addCursor(Cursor *cursor)
0044 {
0045     Q_ASSERT(!m_cursors.contains(cursor));
0046     m_cursors += cursor;
0047 
0048     connect(cursor, &Cursor::posChanged, this, [this, cursor](const QPointF &pos) {
0049         setCurrentCursor(cursor);
0050         Q_EMIT positionChanged(cursor, pos);
0051     });
0052 }
0053 
0054 void Cursors::removeCursor(Cursor *cursor)
0055 {
0056     m_cursors.removeOne(cursor);
0057     if (m_currentCursor == cursor) {
0058         if (m_cursors.isEmpty()) {
0059             m_currentCursor = nullptr;
0060         } else {
0061             setCurrentCursor(m_cursors.constFirst());
0062         }
0063     }
0064     if (m_mouse == cursor) {
0065         m_mouse = nullptr;
0066     }
0067 }
0068 
0069 void Cursors::hideCursor()
0070 {
0071     m_cursorHideCounter++;
0072     if (m_cursorHideCounter == 1) {
0073         Q_EMIT hiddenChanged();
0074     }
0075 }
0076 
0077 void Cursors::showCursor()
0078 {
0079     m_cursorHideCounter--;
0080     if (m_cursorHideCounter == 0) {
0081         Q_EMIT hiddenChanged();
0082     }
0083 }
0084 
0085 bool Cursors::isCursorHidden() const
0086 {
0087     return m_cursorHideCounter > 0;
0088 }
0089 
0090 void Cursors::setCurrentCursor(Cursor *cursor)
0091 {
0092     if (m_currentCursor == cursor) {
0093         return;
0094     }
0095 
0096     Q_ASSERT(m_cursors.contains(cursor) || !cursor);
0097 
0098     if (m_currentCursor) {
0099         disconnect(m_currentCursor, &Cursor::cursorChanged, this, &Cursors::emitCurrentCursorChanged);
0100     }
0101     m_currentCursor = cursor;
0102     connect(m_currentCursor, &Cursor::cursorChanged, this, &Cursors::emitCurrentCursorChanged);
0103 
0104     Q_EMIT currentCursorChanged(m_currentCursor);
0105 }
0106 
0107 void Cursors::emitCurrentCursorChanged()
0108 {
0109     Q_EMIT currentCursorChanged(m_currentCursor);
0110 }
0111 
0112 Cursor::Cursor()
0113     : m_mousePollingCounter(0)
0114     , m_cursorTrackingCounter(0)
0115     , m_themeName(defaultThemeName())
0116     , m_themeSize(defaultThemeSize())
0117 {
0118     loadThemeSettings();
0119     QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"),
0120                                           QStringLiteral("notifyChange"), this, SLOT(slotKGlobalSettingsNotifyChange(int, int)));
0121 
0122     if (kwinApp()->operationMode() != Application::OperationModeWaylandOnly) {
0123         connect(kwinApp(), &Application::x11ConnectionChanged, this, [this]() {
0124             m_cursors.clear();
0125         });
0126     }
0127 }
0128 
0129 Cursor::~Cursor()
0130 {
0131     Cursors::self()->removeCursor(this);
0132 }
0133 
0134 void Cursor::loadThemeSettings()
0135 {
0136     QString themeName = QString::fromUtf8(qgetenv("XCURSOR_THEME"));
0137     bool ok = false;
0138     // XCURSOR_SIZE might not be set (e.g. by startkde)
0139     const uint themeSize = qEnvironmentVariableIntValue("XCURSOR_SIZE", &ok);
0140     if (!themeName.isEmpty() && ok) {
0141         updateTheme(themeName, themeSize);
0142         return;
0143     }
0144     // didn't get from environment variables, read from config file
0145     loadThemeFromKConfig();
0146 }
0147 
0148 void Cursor::loadThemeFromKConfig()
0149 {
0150     KConfigGroup mousecfg(kwinApp()->inputConfig(), QStringLiteral("Mouse"));
0151     const QString themeName = mousecfg.readEntry("cursorTheme", defaultThemeName());
0152     const uint themeSize = mousecfg.readEntry("cursorSize", defaultThemeSize());
0153     updateTheme(themeName, themeSize);
0154 }
0155 
0156 void Cursor::updateTheme(const QString &name, int size)
0157 {
0158     if (m_themeName != name || m_themeSize != size) {
0159         m_themeName = name;
0160         m_themeSize = size;
0161         m_cursors.clear();
0162         Q_EMIT themeChanged();
0163     }
0164 }
0165 
0166 void Cursor::slotKGlobalSettingsNotifyChange(int type, int arg)
0167 {
0168     if (type == 5 /*CursorChanged*/) {
0169         kwinApp()->inputConfig()->reparseConfiguration();
0170         loadThemeFromKConfig();
0171     }
0172 }
0173 
0174 bool Cursor::isOnOutput(Output *output) const
0175 {
0176     if (Cursors::self()->isCursorHidden()) {
0177         return false;
0178     }
0179     return geometry().intersects(output->geometry());
0180 }
0181 
0182 QPointF Cursor::hotspot() const
0183 {
0184     if (Q_UNLIKELY(!m_source)) {
0185         return QPointF();
0186     }
0187     return m_source->hotspot();
0188 }
0189 
0190 QRectF Cursor::geometry() const
0191 {
0192     return rect().translated(m_pos - hotspot());
0193 }
0194 
0195 QRectF Cursor::rect() const
0196 {
0197     if (Q_UNLIKELY(!m_source)) {
0198         return QRectF();
0199     } else {
0200         return QRectF(QPointF(0, 0), m_source->size());
0201     }
0202 }
0203 
0204 QPointF Cursor::pos()
0205 {
0206     doGetPos();
0207     return m_pos;
0208 }
0209 
0210 void Cursor::setPos(const QPointF &pos)
0211 {
0212     // first query the current pos to not warp to the already existing pos
0213     if (pos == m_pos) {
0214         return;
0215     }
0216     m_pos = pos;
0217     doSetPos();
0218 }
0219 
0220 void Cursor::markAsRendered(std::chrono::milliseconds timestamp)
0221 {
0222     Q_EMIT rendered(timestamp);
0223 }
0224 
0225 xcb_cursor_t Cursor::x11Cursor(CursorShape shape)
0226 {
0227     return x11Cursor(shape.name());
0228 }
0229 
0230 xcb_cursor_t Cursor::x11Cursor(const QByteArray &name)
0231 {
0232     Q_ASSERT(kwinApp()->x11Connection());
0233     auto it = m_cursors.constFind(name);
0234     if (it != m_cursors.constEnd()) {
0235         return it.value();
0236     }
0237 
0238     if (name.isEmpty()) {
0239         return XCB_CURSOR_NONE;
0240     }
0241 
0242     xcb_cursor_context_t *ctx;
0243     if (xcb_cursor_context_new(kwinApp()->x11Connection(), Xcb::defaultScreen(), &ctx) < 0) {
0244         return XCB_CURSOR_NONE;
0245     }
0246 
0247     xcb_cursor_t cursor = xcb_cursor_load_cursor(ctx, name.constData());
0248     if (cursor == XCB_CURSOR_NONE) {
0249         const auto &names = CursorShape::alternatives(name);
0250         for (const QByteArray &cursorName : names) {
0251             cursor = xcb_cursor_load_cursor(ctx, cursorName.constData());
0252             if (cursor != XCB_CURSOR_NONE) {
0253                 break;
0254             }
0255         }
0256     }
0257     if (cursor != XCB_CURSOR_NONE) {
0258         m_cursors.insert(name, cursor);
0259     }
0260 
0261     xcb_cursor_context_free(ctx);
0262     return cursor;
0263 }
0264 
0265 void Cursor::doSetPos()
0266 {
0267     Q_EMIT posChanged(m_pos);
0268 }
0269 
0270 void Cursor::doGetPos()
0271 {
0272 }
0273 
0274 void Cursor::updatePos(const QPointF &pos)
0275 {
0276     if (m_pos == pos) {
0277         return;
0278     }
0279     m_pos = pos;
0280     Q_EMIT posChanged(m_pos);
0281 }
0282 
0283 void Cursor::startMousePolling()
0284 {
0285     ++m_mousePollingCounter;
0286     if (m_mousePollingCounter == 1) {
0287         doStartMousePolling();
0288     }
0289 }
0290 
0291 void Cursor::stopMousePolling()
0292 {
0293     Q_ASSERT(m_mousePollingCounter > 0);
0294     --m_mousePollingCounter;
0295     if (m_mousePollingCounter == 0) {
0296         doStopMousePolling();
0297     }
0298 }
0299 
0300 void Cursor::doStartMousePolling()
0301 {
0302 }
0303 
0304 void Cursor::doStopMousePolling()
0305 {
0306 }
0307 
0308 void Cursor::startCursorTracking()
0309 {
0310     ++m_cursorTrackingCounter;
0311     if (m_cursorTrackingCounter == 1) {
0312         doStartCursorTracking();
0313     }
0314 }
0315 
0316 void Cursor::stopCursorTracking()
0317 {
0318     Q_ASSERT(m_cursorTrackingCounter > 0);
0319     --m_cursorTrackingCounter;
0320     if (m_cursorTrackingCounter == 0) {
0321         doStopCursorTracking();
0322     }
0323 }
0324 
0325 void Cursor::doStartCursorTracking()
0326 {
0327 }
0328 
0329 void Cursor::doStopCursorTracking()
0330 {
0331 }
0332 
0333 QString Cursor::defaultThemeName()
0334 {
0335     return QStringLiteral("default");
0336 }
0337 
0338 int Cursor::defaultThemeSize()
0339 {
0340     return 24;
0341 }
0342 
0343 QList<QByteArray> CursorShape::alternatives(const QByteArray &name)
0344 {
0345     static const QHash<QByteArray, QList<QByteArray>> alternatives = {
0346         {
0347             QByteArrayLiteral("crosshair"),
0348             {
0349                 QByteArrayLiteral("cross"),
0350                 QByteArrayLiteral("diamond-cross"),
0351                 QByteArrayLiteral("cross-reverse"),
0352             },
0353         },
0354         {
0355             QByteArrayLiteral("default"),
0356             {
0357                 QByteArrayLiteral("left_ptr"),
0358                 QByteArrayLiteral("arrow"),
0359                 QByteArrayLiteral("dnd-none"),
0360                 QByteArrayLiteral("op_left_arrow"),
0361             },
0362         },
0363         {
0364             QByteArrayLiteral("up-arrow"),
0365             {
0366                 QByteArrayLiteral("up_arrow"),
0367                 QByteArrayLiteral("sb_up_arrow"),
0368                 QByteArrayLiteral("center_ptr"),
0369                 QByteArrayLiteral("centre_ptr"),
0370             },
0371         },
0372         {
0373             QByteArrayLiteral("wait"),
0374             {
0375                 QByteArrayLiteral("watch"),
0376                 QByteArrayLiteral("progress"),
0377             },
0378         },
0379         {
0380             QByteArrayLiteral("text"),
0381             {
0382                 QByteArrayLiteral("ibeam"),
0383                 QByteArrayLiteral("xterm"),
0384             },
0385         },
0386         {
0387             QByteArrayLiteral("all-scroll"),
0388             {
0389                 QByteArrayLiteral("size_all"),
0390                 QByteArrayLiteral("fleur"),
0391             },
0392         },
0393         {
0394             QByteArrayLiteral("pointer"),
0395             {
0396                 QByteArrayLiteral("pointing_hand"),
0397                 QByteArrayLiteral("hand2"),
0398                 QByteArrayLiteral("hand"),
0399                 QByteArrayLiteral("hand1"),
0400                 QByteArrayLiteral("e29285e634086352946a0e7090d73106"),
0401                 QByteArrayLiteral("9d800788f1b08800ae810202380a0822"),
0402             },
0403         },
0404         {
0405             QByteArrayLiteral("ns-resize"),
0406             {
0407                 QByteArrayLiteral("size_ver"),
0408                 QByteArrayLiteral("00008160000006810000408080010102"),
0409                 QByteArrayLiteral("sb_v_double_arrow"),
0410                 QByteArrayLiteral("v_double_arrow"),
0411                 QByteArrayLiteral("n-resize"),
0412                 QByteArrayLiteral("s-resize"),
0413                 QByteArrayLiteral("col-resize"),
0414                 QByteArrayLiteral("top_side"),
0415                 QByteArrayLiteral("bottom_side"),
0416                 QByteArrayLiteral("base_arrow_up"),
0417                 QByteArrayLiteral("base_arrow_down"),
0418                 QByteArrayLiteral("based_arrow_down"),
0419                 QByteArrayLiteral("based_arrow_up"),
0420             },
0421         },
0422         {
0423             QByteArrayLiteral("ew-resize"),
0424             {
0425                 QByteArrayLiteral("size_hor"),
0426                 QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"),
0427                 QByteArrayLiteral("sb_h_double_arrow"),
0428                 QByteArrayLiteral("h_double_arrow"),
0429                 QByteArrayLiteral("e-resize"),
0430                 QByteArrayLiteral("w-resize"),
0431                 QByteArrayLiteral("row-resize"),
0432                 QByteArrayLiteral("right_side"),
0433                 QByteArrayLiteral("left_side"),
0434             },
0435         },
0436         {
0437             QByteArrayLiteral("nesw-resize"),
0438             {
0439                 QByteArrayLiteral("size_bdiag"),
0440                 QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"),
0441                 QByteArrayLiteral("fd_double_arrow"),
0442                 QByteArrayLiteral("bottom_left_corner"),
0443                 QByteArrayLiteral("top_right_corner"),
0444             },
0445         },
0446         {
0447             QByteArrayLiteral("nwse-resize"),
0448             {
0449                 QByteArrayLiteral("size_fdiag"),
0450                 QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"),
0451                 QByteArrayLiteral("bd_double_arrow"),
0452                 QByteArrayLiteral("bottom_right_corner"),
0453                 QByteArrayLiteral("top_left_corner"),
0454             },
0455         },
0456         {
0457             QByteArrayLiteral("help"),
0458             {
0459                 QByteArrayLiteral("whats_this"),
0460                 QByteArrayLiteral("d9ce0ab605698f320427677b458ad60b"),
0461                 QByteArrayLiteral("left_ptr_help"),
0462                 QByteArrayLiteral("question_arrow"),
0463                 QByteArrayLiteral("dnd-ask"),
0464                 QByteArrayLiteral("5c6cd98b3f3ebcb1f9c7f1c204630408"),
0465             },
0466         },
0467         {
0468             QByteArrayLiteral("col-resize"),
0469             {
0470                 QByteArrayLiteral("split_h"),
0471                 QByteArrayLiteral("14fef782d02440884392942c11205230"),
0472                 QByteArrayLiteral("size_hor"),
0473             },
0474         },
0475         {
0476             QByteArrayLiteral("row-resize"),
0477             {
0478                 QByteArrayLiteral("split_v"),
0479                 QByteArrayLiteral("2870a09082c103050810ffdffffe0204"),
0480                 QByteArrayLiteral("size_ver"),
0481             },
0482         },
0483         {
0484             QByteArrayLiteral("not-allowed"),
0485             {
0486                 QByteArrayLiteral("forbidden"),
0487                 QByteArrayLiteral("03b6e0fcb3499374a867c041f52298f0"),
0488                 QByteArrayLiteral("circle"),
0489                 QByteArrayLiteral("dnd-no-drop"),
0490             },
0491         },
0492         {
0493             QByteArrayLiteral("progress"),
0494             {
0495                 QByteArrayLiteral("left_ptr_watch"),
0496                 QByteArrayLiteral("3ecb610c1bf2410f44200f48c40d3599"),
0497                 QByteArrayLiteral("00000000000000020006000e7e9ffc3f"),
0498                 QByteArrayLiteral("08e8e1c95fe2fc01f976f1e063a24ccd"),
0499             },
0500         },
0501         {
0502             QByteArrayLiteral("grab"),
0503             {
0504                 QByteArrayLiteral("openhand"),
0505                 QByteArrayLiteral("9141b49c8149039304290b508d208c40"),
0506                 QByteArrayLiteral("all_scroll"),
0507                 QByteArrayLiteral("all-scroll"),
0508             },
0509         },
0510         {
0511             QByteArrayLiteral("grabbing"),
0512             {
0513                 QByteArrayLiteral("closedhand"),
0514                 QByteArrayLiteral("05e88622050804100c20044008402080"),
0515                 QByteArrayLiteral("4498f0e0c1937ffe01fd06f973665830"),
0516                 QByteArrayLiteral("9081237383d90e509aa00f00170e968f"),
0517                 QByteArrayLiteral("fcf21c00b30f7e3f83fe0dfd12e71cff"),
0518             },
0519         },
0520         {
0521             QByteArrayLiteral("alias"),
0522             {
0523                 QByteArrayLiteral("link"),
0524                 QByteArrayLiteral("dnd-link"),
0525                 QByteArrayLiteral("3085a0e285430894940527032f8b26df"),
0526                 QByteArrayLiteral("640fb0e74195791501fd1ed57b41487f"),
0527                 QByteArrayLiteral("a2a266d0498c3104214a47bd64ab0fc8"),
0528             },
0529         },
0530         {
0531             QByteArrayLiteral("copy"),
0532             {
0533                 QByteArrayLiteral("dnd-copy"),
0534                 QByteArrayLiteral("1081e37283d90000800003c07f3ef6bf"),
0535                 QByteArrayLiteral("6407b0e94181790501fd1e167b474872"),
0536                 QByteArrayLiteral("b66166c04f8c3109214a4fbd64a50fc8"),
0537             },
0538         },
0539         {
0540             QByteArrayLiteral("move"),
0541             {
0542                 QByteArrayLiteral("dnd-move"),
0543             },
0544         },
0545         {
0546             QByteArrayLiteral("sw-resize"),
0547             {
0548                 QByteArrayLiteral("size_bdiag"),
0549                 QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"),
0550                 QByteArrayLiteral("fd_double_arrow"),
0551                 QByteArrayLiteral("bottom_left_corner"),
0552             },
0553         },
0554         {
0555             QByteArrayLiteral("se-resize"),
0556             {
0557                 QByteArrayLiteral("size_fdiag"),
0558                 QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"),
0559                 QByteArrayLiteral("bd_double_arrow"),
0560                 QByteArrayLiteral("bottom_right_corner"),
0561             },
0562         },
0563         {
0564             QByteArrayLiteral("ne-resize"),
0565             {
0566                 QByteArrayLiteral("size_bdiag"),
0567                 QByteArrayLiteral("fcf1c3c7cd4491d801f1e1c78f100000"),
0568                 QByteArrayLiteral("fd_double_arrow"),
0569                 QByteArrayLiteral("top_right_corner"),
0570             },
0571         },
0572         {
0573             QByteArrayLiteral("nw-resize"),
0574             {
0575                 QByteArrayLiteral("size_fdiag"),
0576                 QByteArrayLiteral("c7088f0f3e6c8088236ef8e1e3e70000"),
0577                 QByteArrayLiteral("bd_double_arrow"),
0578                 QByteArrayLiteral("top_left_corner"),
0579             },
0580         },
0581         {
0582             QByteArrayLiteral("n-resize"),
0583             {
0584                 QByteArrayLiteral("size_ver"),
0585                 QByteArrayLiteral("00008160000006810000408080010102"),
0586                 QByteArrayLiteral("sb_v_double_arrow"),
0587                 QByteArrayLiteral("v_double_arrow"),
0588                 QByteArrayLiteral("col-resize"),
0589                 QByteArrayLiteral("top_side"),
0590             },
0591         },
0592         {
0593             QByteArrayLiteral("e-resize"),
0594             {
0595                 QByteArrayLiteral("size_hor"),
0596                 QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"),
0597                 QByteArrayLiteral("sb_h_double_arrow"),
0598                 QByteArrayLiteral("h_double_arrow"),
0599                 QByteArrayLiteral("row-resize"),
0600                 QByteArrayLiteral("left_side"),
0601             },
0602         },
0603         {
0604             QByteArrayLiteral("s-resize"),
0605             {
0606                 QByteArrayLiteral("size_ver"),
0607                 QByteArrayLiteral("00008160000006810000408080010102"),
0608                 QByteArrayLiteral("sb_v_double_arrow"),
0609                 QByteArrayLiteral("v_double_arrow"),
0610                 QByteArrayLiteral("col-resize"),
0611                 QByteArrayLiteral("bottom_side"),
0612             },
0613         },
0614         {
0615             QByteArrayLiteral("w-resize"),
0616             {
0617                 QByteArrayLiteral("size_hor"),
0618                 QByteArrayLiteral("028006030e0e7ebffc7f7070c0600140"),
0619                 QByteArrayLiteral("sb_h_double_arrow"),
0620                 QByteArrayLiteral("h_double_arrow"),
0621                 QByteArrayLiteral("right_side"),
0622             },
0623         },
0624     };
0625     auto it = alternatives.find(name);
0626     if (it != alternatives.end()) {
0627         return it.value();
0628     }
0629     return QList<QByteArray>();
0630 }
0631 
0632 QByteArray CursorShape::name() const
0633 {
0634     switch (m_shape) {
0635     case Qt::ArrowCursor:
0636         return QByteArrayLiteral("default");
0637     case Qt::UpArrowCursor:
0638         return QByteArrayLiteral("up-arrow");
0639     case Qt::CrossCursor:
0640         return QByteArrayLiteral("crosshair");
0641     case Qt::WaitCursor:
0642         return QByteArrayLiteral("wait");
0643     case Qt::IBeamCursor:
0644         return QByteArrayLiteral("text");
0645     case Qt::SizeVerCursor:
0646         return QByteArrayLiteral("ns-resize");
0647     case Qt::SizeHorCursor:
0648         return QByteArrayLiteral("ew-resize");
0649     case Qt::SizeBDiagCursor:
0650         return QByteArrayLiteral("nesw-resize");
0651     case Qt::SizeFDiagCursor:
0652         return QByteArrayLiteral("nwse-resize");
0653     case Qt::SizeAllCursor:
0654         return QByteArrayLiteral("all-scroll");
0655     case Qt::SplitVCursor:
0656         return QByteArrayLiteral("row-resize");
0657     case Qt::SplitHCursor:
0658         return QByteArrayLiteral("col-resize");
0659     case Qt::PointingHandCursor:
0660         return QByteArrayLiteral("pointer");
0661     case Qt::ForbiddenCursor:
0662         return QByteArrayLiteral("not-allowed");
0663     case Qt::OpenHandCursor:
0664         return QByteArrayLiteral("grab");
0665     case Qt::ClosedHandCursor:
0666         return QByteArrayLiteral("grabbing");
0667     case Qt::WhatsThisCursor:
0668         return QByteArrayLiteral("help");
0669     case Qt::BusyCursor:
0670         return QByteArrayLiteral("progress");
0671     case Qt::DragMoveCursor:
0672         return QByteArrayLiteral("move");
0673     case Qt::DragCopyCursor:
0674         return QByteArrayLiteral("copy");
0675     case Qt::DragLinkCursor:
0676         return QByteArrayLiteral("alias");
0677     case KWin::ExtendedCursor::SizeNorthEast:
0678         return QByteArrayLiteral("ne-resize");
0679     case KWin::ExtendedCursor::SizeNorth:
0680         return QByteArrayLiteral("n-resize");
0681     case KWin::ExtendedCursor::SizeNorthWest:
0682         return QByteArrayLiteral("nw-resize");
0683     case KWin::ExtendedCursor::SizeEast:
0684         return QByteArrayLiteral("e-resize");
0685     case KWin::ExtendedCursor::SizeWest:
0686         return QByteArrayLiteral("w-resize");
0687     case KWin::ExtendedCursor::SizeSouthEast:
0688         return QByteArrayLiteral("se-resize");
0689     case KWin::ExtendedCursor::SizeSouth:
0690         return QByteArrayLiteral("s-resize");
0691     case KWin::ExtendedCursor::SizeSouthWest:
0692         return QByteArrayLiteral("sw-resize");
0693     default:
0694         return QByteArray();
0695     }
0696 }
0697 
0698 CursorSource *Cursor::source() const
0699 {
0700     return m_source;
0701 }
0702 
0703 void Cursor::setSource(CursorSource *source)
0704 {
0705     if (m_source == source) {
0706         return;
0707     }
0708     if (m_source) {
0709         disconnect(m_source, &CursorSource::changed, this, &Cursor::cursorChanged);
0710     }
0711     m_source = source;
0712     connect(m_source, &CursorSource::changed, this, &Cursor::cursorChanged);
0713     Q_EMIT cursorChanged();
0714 }
0715 
0716 } // namespace
0717 
0718 #include "moc_cursor.cpp"