File indexing completed on 2024-12-01 13:37:21
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 <kwinglobals.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(QObject *parent); 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 QVector<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 QPoint pos(); 0160 /** 0161 * Warps the mouse cursor to new @p pos. 0162 * Values will be rounded to an integer 0163 */ 0164 void setPos(const QPointF &pos); 0165 /** 0166 * Warps the mouse cursor to new @p pos. 0167 */ 0168 void setPos(const QPoint &pos); 0169 void setPos(int x, int y); 0170 xcb_cursor_t x11Cursor(CursorShape shape); 0171 /** 0172 * Notice: if available always use the CursorShape variant to avoid cache duplicates for 0173 * ambiguous cursor names in the non existing cursor name specification 0174 */ 0175 xcb_cursor_t x11Cursor(const QByteArray &name); 0176 0177 QImage image() const; 0178 QPoint hotspot() const; 0179 QRect geometry() const; 0180 QRect rect() const; 0181 0182 CursorSource *source() const; 0183 void setSource(CursorSource *source); 0184 0185 /** 0186 * Returns @c true if the cursor is visible on the given output; otherwise returns @c false. 0187 */ 0188 bool isOnOutput(Output *output) const; 0189 0190 void markAsRendered(std::chrono::milliseconds timestamp); 0191 0192 Q_SIGNALS: 0193 void posChanged(const QPoint &pos); 0194 void mouseChanged(const QPoint &pos, const QPoint &oldpos, 0195 Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, 0196 Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers); 0197 /** 0198 * @brief Signal emitted when the cursor image changes. 0199 * 0200 * To enable these signals use startCursorTracking. 0201 * 0202 * @see startCursorTracking 0203 * @see stopCursorTracking 0204 */ 0205 void cursorChanged(); 0206 void themeChanged(); 0207 void rendered(std::chrono::milliseconds timestamp); 0208 0209 protected: 0210 /** 0211 * Performs the actual warping of the cursor. 0212 */ 0213 virtual void doSetPos(); 0214 /** 0215 * Called from @ref pos() to allow syncing the internal position with the underlying 0216 * system's cursor position. 0217 */ 0218 virtual void doGetPos(); 0219 /** 0220 * Called from startMousePolling when the mouse polling gets activated. Base implementation 0221 * does nothing, inheriting classes can overwrite to e.g. start a timer. 0222 */ 0223 virtual void doStartMousePolling(); 0224 /** 0225 * Called from stopMousePolling when the mouse polling gets deactivated. Base implementation 0226 * does nothing, inheriting classes can overwrite to e.g. stop a timer. 0227 */ 0228 virtual void doStopMousePolling(); 0229 /** 0230 * Called from startCursorTracking when cursor image tracking gets activated. Inheriting class needs 0231 * to overwrite to enable platform specific code for the tracking. 0232 */ 0233 virtual void doStartCursorTracking(); 0234 /** 0235 * Called from stopCursorTracking when cursor image tracking gets deactivated. Inheriting class needs 0236 * to overwrite to disable platform specific code for the tracking. 0237 */ 0238 virtual void doStopCursorTracking(); 0239 bool isCursorTracking() const; 0240 /** 0241 * Provides the actual internal cursor position to inheriting classes. If an inheriting class needs 0242 * access to the cursor position this method should be used instead of the static @ref pos, as 0243 * the static method syncs with the underlying system's cursor. 0244 */ 0245 const QPoint ¤tPos() const; 0246 /** 0247 * Updates the internal position to @p pos without warping the pointer as 0248 * setPos does. 0249 */ 0250 void updatePos(const QPoint &pos); 0251 void updatePos(int x, int y); 0252 0253 private Q_SLOTS: 0254 void loadThemeSettings(); 0255 void slotKGlobalSettingsNotifyChange(int type, int arg); 0256 0257 private: 0258 void updateTheme(const QString &name, int size); 0259 void loadThemeFromKConfig(); 0260 CursorSource *m_source = nullptr; 0261 QHash<QByteArray, xcb_cursor_t> m_cursors; 0262 QPoint m_pos; 0263 int m_mousePollingCounter; 0264 int m_cursorTrackingCounter; 0265 QString m_themeName; 0266 int m_themeSize; 0267 }; 0268 0269 class KWIN_EXPORT Cursors : public QObject 0270 { 0271 Q_OBJECT 0272 public: 0273 Cursor *mouse() const 0274 { 0275 return m_mouse; 0276 } 0277 0278 void setMouse(Cursor *mouse) 0279 { 0280 if (m_mouse != mouse) { 0281 m_mouse = mouse; 0282 0283 addCursor(m_mouse); 0284 setCurrentCursor(m_mouse); 0285 } 0286 } 0287 0288 void addCursor(Cursor *cursor); 0289 void removeCursor(Cursor *cursor); 0290 0291 ///@returns the last cursor that moved 0292 Cursor *currentCursor() const 0293 { 0294 return m_currentCursor; 0295 } 0296 0297 void hideCursor(); 0298 void showCursor(); 0299 bool isCursorHidden() const; 0300 0301 static Cursors *self(); 0302 0303 Q_SIGNALS: 0304 void currentCursorChanged(Cursor *cursor); 0305 void hiddenChanged(); 0306 void positionChanged(Cursor *cursor, const QPoint &position); 0307 0308 private: 0309 void emitCurrentCursorChanged(); 0310 void setCurrentCursor(Cursor *cursor); 0311 0312 static Cursors *s_self; 0313 Cursor *m_currentCursor = nullptr; 0314 Cursor *m_mouse = nullptr; 0315 QVector<Cursor *> m_cursors; 0316 int m_cursorHideCounter = 0; 0317 }; 0318 0319 class InputConfig 0320 { 0321 public: 0322 KSharedConfigPtr inputConfig() const 0323 { 0324 return m_inputConfig; 0325 } 0326 void setInputConfig(KSharedConfigPtr config) 0327 { 0328 m_inputConfig = std::move(config); 0329 } 0330 0331 static InputConfig *self(); 0332 0333 private: 0334 InputConfig(); 0335 0336 KSharedConfigPtr m_inputConfig; 0337 static InputConfig *s_self; 0338 }; 0339 0340 inline const QPoint &Cursor::currentPos() const 0341 { 0342 return m_pos; 0343 } 0344 0345 inline void Cursor::updatePos(int x, int y) 0346 { 0347 updatePos(QPoint(x, y)); 0348 } 0349 0350 inline const QString &Cursor::themeName() const 0351 { 0352 return m_themeName; 0353 } 0354 0355 inline int Cursor::themeSize() const 0356 { 0357 return m_themeSize; 0358 } 0359 0360 inline bool Cursor::isCursorTracking() const 0361 { 0362 return m_cursorTrackingCounter > 0; 0363 } 0364 0365 } 0366 0367 Q_DECLARE_METATYPE(KWin::CursorShape)