File indexing completed on 2025-03-23 05:02:45
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 ¤tPos() 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)