File indexing completed on 2024-04-28 16:48:41

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