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