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 #pragma once
0010 // kwin
0011 #include "effect/globals.h"
0012 // Qt
0013 #include <QHash>
0014 #include <QObject>
0015 #include <QPoint>
0016 // KF
0017 #include <KSharedConfig>
0018 // xcb
0019 #include <xcb/xcb.h>
0020 
0021 class QTimer;
0022 
0023 namespace KWin
0024 {
0025 
0026 class CursorSource;
0027 class Output;
0028 
0029 namespace ExtendedCursor
0030 {
0031 /**
0032  * Extension of Qt::CursorShape with values not currently present there
0033  */
0034 enum Shape {
0035     SizeNorthWest = 0x100 + 0,
0036     SizeNorth = 0x100 + 1,
0037     SizeNorthEast = 0x100 + 2,
0038     SizeEast = 0x100 + 3,
0039     SizeWest = 0x100 + 4,
0040     SizeSouthEast = 0x100 + 5,
0041     SizeSouth = 0x100 + 6,
0042     SizeSouthWest = 0x100 + 7
0043 };
0044 }
0045 
0046 /**
0047  * @brief Wrapper round Qt::CursorShape with extensions enums into a single entity
0048  */
0049 class KWIN_EXPORT CursorShape
0050 {
0051 public:
0052     CursorShape() = default;
0053     CursorShape(Qt::CursorShape qtShape)
0054     {
0055         m_shape = qtShape;
0056     }
0057     CursorShape(KWin::ExtendedCursor::Shape kwinShape)
0058     {
0059         m_shape = kwinShape;
0060     }
0061     bool operator==(const CursorShape &o) const
0062     {
0063         return m_shape == o.m_shape;
0064     }
0065     operator int() const
0066     {
0067         return m_shape;
0068     }
0069     /**
0070      * @brief The name of a cursor shape in the theme.
0071      */
0072     QByteArray name() const;
0073 
0074     /**
0075      * Returns the list of alternative shape names for a shape with the specified @a name.
0076      */
0077     static QList<QByteArray> alternatives(const QByteArray &name);
0078 
0079 private:
0080     int m_shape = Qt::ArrowCursor;
0081 };
0082 
0083 /**
0084  * @short Replacement for QCursor.
0085  *
0086  * This class provides a similar API to QCursor and should be preferred inside KWin. It allows to
0087  * get the position and warp the mouse cursor with static methods just like QCursor. It also provides
0088  * the possibility to get an X11 cursor for a Qt::CursorShape - a functionality lost in Qt 5's QCursor
0089  * implementation.
0090  *
0091  * In addition the class provides a mouse polling facility as required by e.g. Effects and ScreenEdges
0092  * and emits signals when the mouse position changes. In opposite to QCursor this class is a QObject
0093  * and cannot be constructed. Instead it provides a singleton getter, though the most important
0094  * methods are wrapped in a static method, just like QCursor.
0095  *
0096  * The actual implementation is split into two parts: a system independent interface and a windowing
0097  * system specific subclass. So far only an X11 backend is implemented which uses query pointer to
0098  * fetch the position and warp pointer to set the position. It uses a timer based mouse polling and
0099  * can provide X11 cursors through the XCursor library.
0100  */
0101 class KWIN_EXPORT Cursor : public QObject
0102 {
0103     Q_OBJECT
0104 public:
0105     Cursor();
0106     ~Cursor() override;
0107     void startMousePolling();
0108     void stopMousePolling();
0109     /**
0110      * @brief Enables tracking changes of cursor images.
0111      *
0112      * After enabling cursor change tracking the signal cursorChanged will be emitted
0113      * whenever a change to the cursor image is recognized.
0114      *
0115      * Use stopCursorTracking to no longer emit this signal. Note: the signal will be
0116      * emitted until each call of this method has been matched with a call to stopCursorTracking.
0117      *
0118      * This tracking is not about pointer position tracking.
0119      * @see stopCursorTracking
0120      * @see cursorChanged
0121      */
0122     void startCursorTracking();
0123     /**
0124      * @brief Disables tracking changes of cursor images.
0125      *
0126      * Only call after using startCursorTracking.
0127      *
0128      * @see startCursorTracking
0129      */
0130     void stopCursorTracking();
0131 
0132     /**
0133      * @brief The name of the currently used Cursor theme.
0134      *
0135      * @return const QString&
0136      */
0137     const QString &themeName() const;
0138     /**
0139      * @brief The size of the currently used Cursor theme.
0140      *
0141      * @return int
0142      */
0143     int themeSize() const;
0144     /**
0145      * Returns the default Xcursor theme name.
0146      */
0147     static QString defaultThemeName();
0148     /**
0149      * Returns the default Xcursor theme size.
0150      */
0151     static int defaultThemeSize();
0152 
0153     /**
0154      * Returns the current cursor position. This method does an update of the mouse position if
0155      * needed. It's save to call it multiple times.
0156      *
0157      * Implementing subclasses should prefer to use currentPos which is not performing a check
0158      * for update.
0159      */
0160     QPointF pos();
0161     /**
0162      * Warps the mouse cursor to new @p pos.
0163      */
0164     void setPos(const QPointF &pos);
0165     xcb_cursor_t x11Cursor(CursorShape shape);
0166     /**
0167      * Notice: if available always use the CursorShape variant to avoid cache duplicates for
0168      * ambiguous cursor names in the non existing cursor name specification
0169      */
0170     xcb_cursor_t x11Cursor(const QByteArray &name);
0171 
0172     QPointF hotspot() const;
0173     QRectF geometry() const;
0174     QRectF rect() const;
0175 
0176     CursorSource *source() const;
0177     void setSource(CursorSource *source);
0178 
0179     /**
0180      * Returns @c true if the cursor is visible on the given output; otherwise returns @c false.
0181      */
0182     bool isOnOutput(Output *output) const;
0183 
0184     void markAsRendered(std::chrono::milliseconds timestamp);
0185 
0186 Q_SIGNALS:
0187     void posChanged(const QPointF &pos);
0188     void mouseChanged(const QPointF &pos, const QPointF &oldpos,
0189                       Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons,
0190                       Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers);
0191     /**
0192      * @brief Signal emitted when the cursor image changes.
0193      *
0194      * To enable these signals use startCursorTracking.
0195      *
0196      * @see startCursorTracking
0197      * @see stopCursorTracking
0198      */
0199     void cursorChanged();
0200     void themeChanged();
0201     void rendered(std::chrono::milliseconds timestamp);
0202 
0203 protected:
0204     /**
0205      * Performs the actual warping of the cursor.
0206      */
0207     virtual void doSetPos();
0208     /**
0209      * Called from @ref pos() to allow syncing the internal position with the underlying
0210      * system's cursor position.
0211      */
0212     virtual void doGetPos();
0213     /**
0214      * Called from startMousePolling when the mouse polling gets activated. Base implementation
0215      * does nothing, inheriting classes can overwrite to e.g. start a timer.
0216      */
0217     virtual void doStartMousePolling();
0218     /**
0219      * Called from stopMousePolling when the mouse polling gets deactivated. Base implementation
0220      * does nothing, inheriting classes can overwrite to e.g. stop a timer.
0221      */
0222     virtual void doStopMousePolling();
0223     /**
0224      * Called from startCursorTracking when cursor image tracking gets activated. Inheriting class needs
0225      * to overwrite to enable platform specific code for the tracking.
0226      */
0227     virtual void doStartCursorTracking();
0228     /**
0229      * Called from stopCursorTracking when cursor image tracking gets deactivated. Inheriting class needs
0230      * to overwrite to disable platform specific code for the tracking.
0231      */
0232     virtual void doStopCursorTracking();
0233     bool isCursorTracking() const;
0234     /**
0235      * Provides the actual internal cursor position to inheriting classes. If an inheriting class needs
0236      * access to the cursor position this method should be used instead of the static @ref pos, as
0237      * the static method syncs with the underlying system's cursor.
0238      */
0239     const QPointF &currentPos() const;
0240     /**
0241      * Updates the internal position to @p pos without warping the pointer as
0242      * setPos does.
0243      */
0244     void updatePos(const QPointF &pos);
0245 
0246 private Q_SLOTS:
0247     void loadThemeSettings();
0248     void slotKGlobalSettingsNotifyChange(int type, int arg);
0249 
0250 private:
0251     void updateTheme(const QString &name, int size);
0252     void loadThemeFromKConfig();
0253     CursorSource *m_source = nullptr;
0254     QHash<QByteArray, xcb_cursor_t> m_cursors;
0255     QPointF m_pos;
0256     int m_mousePollingCounter;
0257     int m_cursorTrackingCounter;
0258     QString m_themeName;
0259     int m_themeSize;
0260 };
0261 
0262 class KWIN_EXPORT Cursors : public QObject
0263 {
0264     Q_OBJECT
0265 public:
0266     Cursor *mouse() const
0267     {
0268         return m_mouse;
0269     }
0270 
0271     void setMouse(Cursor *mouse)
0272     {
0273         if (m_mouse != mouse) {
0274             m_mouse = mouse;
0275 
0276             addCursor(m_mouse);
0277             setCurrentCursor(m_mouse);
0278         }
0279     }
0280 
0281     void addCursor(Cursor *cursor);
0282     void removeCursor(Cursor *cursor);
0283 
0284     ///@returns the last cursor that moved
0285     Cursor *currentCursor() const
0286     {
0287         return m_currentCursor;
0288     }
0289 
0290     void hideCursor();
0291     void showCursor();
0292     bool isCursorHidden() const;
0293 
0294     static Cursors *self();
0295 
0296 Q_SIGNALS:
0297     void currentCursorChanged(Cursor *cursor);
0298     void hiddenChanged();
0299     void positionChanged(Cursor *cursor, const QPointF &position);
0300 
0301 private:
0302     void emitCurrentCursorChanged();
0303     void setCurrentCursor(Cursor *cursor);
0304 
0305     static Cursors *s_self;
0306     Cursor *m_currentCursor = nullptr;
0307     Cursor *m_mouse = nullptr;
0308     QList<Cursor *> m_cursors;
0309     int m_cursorHideCounter = 0;
0310 };
0311 
0312 inline const QPointF &Cursor::currentPos() const
0313 {
0314     return m_pos;
0315 }
0316 
0317 inline const QString &Cursor::themeName() const
0318 {
0319     return m_themeName;
0320 }
0321 
0322 inline int Cursor::themeSize() const
0323 {
0324     return m_themeSize;
0325 }
0326 
0327 inline bool Cursor::isCursorTracking() const
0328 {
0329     return m_cursorTrackingCounter > 0;
0330 }
0331 
0332 }
0333 
0334 Q_DECLARE_METATYPE(KWin::CursorShape)