1 | /******************************************************************** |
2 | KWin - the KDE window manager |
3 | This file is part of the KDE project. |
4 | |
5 | Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org> |
6 | |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. |
11 | |
12 | This program is distributed in the hope that it will be useful, |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | GNU General Public License for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | *********************************************************************/ |
20 | #ifndef KWIN_CURSOR_H |
21 | #define KWIN_CURSOR_H |
22 | // kwin |
23 | #include <kwinglobals.h> |
24 | // Qt |
25 | #include <QHash> |
26 | #include <QObject> |
27 | #include <QPoint> |
28 | // xcb |
29 | #include <xcb/xcb.h> |
30 | |
31 | class QTimer; |
32 | |
33 | namespace KWin |
34 | { |
35 | |
36 | /** |
37 | * @short Replacement for QCursor. |
38 | * |
39 | * This class provides a similar API to QCursor and should be preferred inside KWin. It allows to |
40 | * get the position and warp the mouse cursor with static methods just like QCursor. It also provides |
41 | * the possibility to get an X11 cursor for a Qt::CursorShape - a functionality lost in Qt 5's QCursor |
42 | * implementation. |
43 | * |
44 | * In addition the class provides a mouse polling facility as required by e.g. Effects and ScreenEdges |
45 | * and emits signals when the mouse position changes. In opposite to QCursor this class is a QObject |
46 | * and cannot be constructed. Instead it provides a singleton getter, though the most important |
47 | * methods are wrapped in a static method, just like QCursor. |
48 | * |
49 | * The actual implementation is split into two parts: a system independent interface and a windowing |
50 | * system specific subclass. So far only an X11 backend is implemented which uses query pointer to |
51 | * fetch the position and warp pointer to set the position. It uses a timer based mouse polling and |
52 | * can provide X11 cursors through the XCursor library. |
53 | **/ |
54 | class Cursor : public QObject |
55 | { |
56 | Q_OBJECT |
57 | public: |
58 | virtual ~Cursor(); |
59 | void startMousePolling(); |
60 | void stopMousePolling(); |
61 | /** |
62 | * @brief Enables tracking changes of cursor images. |
63 | * |
64 | * After enabling cursor change tracking the signal @link cursorChanged will be emitted |
65 | * whenever a change to the cursor image is recognized. |
66 | * |
67 | * Use @link stopCursorTracking to no longer emit this signal. Note: the signal will be |
68 | * emitted until each call of this method has been matched with a call to stopCursorTracking. |
69 | * |
70 | * This tracking is not about pointer position tracking. |
71 | * @see stopCursorTracking |
72 | * @see cursorChanged |
73 | */ |
74 | void startCursorTracking(); |
75 | /** |
76 | * @brief Disables tracking changes of cursor images. |
77 | * |
78 | * Only call after using @link startCursorTracking. |
79 | * |
80 | * @see startCursorTracking |
81 | */ |
82 | void stopCursorTracking(); |
83 | /** |
84 | * @internal |
85 | * |
86 | * Called from X11 event handler. |
87 | */ |
88 | void notifyCursorChanged(uint32_t serial); |
89 | |
90 | /** |
91 | * Returns the current cursor position. This method does an update of the mouse position if |
92 | * needed. It's save to call it multiple times. |
93 | * |
94 | * Implementing subclasses should prefer to use @link currentPos which is not performing a check |
95 | * for update. |
96 | **/ |
97 | static QPoint pos(); |
98 | /** |
99 | * Warps the mouse cursor to new @p pos. |
100 | **/ |
101 | static void setPos(const QPoint &pos); |
102 | static void setPos(int x, int y); |
103 | static xcb_cursor_t x11Cursor(Qt::CursorShape shape); |
104 | |
105 | Q_SIGNALS: |
106 | void posChanged(QPoint pos); |
107 | void mouseChanged(const QPoint& pos, const QPoint& oldpos, |
108 | Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, |
109 | Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers); |
110 | /** |
111 | * @brief Signal emitted when the cursor image changes. |
112 | * |
113 | * To enable these signals use @link startCursorTracking. |
114 | * |
115 | * @param serial The serial number of the new selected cursor. |
116 | * @see startCursorTracking |
117 | * @see stopCursorTracking |
118 | */ |
119 | void cursorChanged(uint32_t serial); |
120 | |
121 | protected: |
122 | /** |
123 | * Called from @link x11Cursor to actually retrieve the X11 cursor. Base implementation returns |
124 | * a null cursor, an implementing subclass should implement this method if it can provide X11 |
125 | * mouse cursors. |
126 | **/ |
127 | virtual xcb_cursor_t getX11Cursor(Qt::CursorShape shape); |
128 | /** |
129 | * Performs the actual warping of the cursor. |
130 | **/ |
131 | virtual void doSetPos(); |
132 | /** |
133 | * Called from @link pos() to allow syncing the internal position with the underlying |
134 | * system's cursor position. |
135 | **/ |
136 | virtual void doGetPos(); |
137 | /** |
138 | * Called from @link startMousePolling when the mouse polling gets activated. Base implementation |
139 | * does nothing, inheriting classes can overwrite to e.g. start a timer. |
140 | **/ |
141 | virtual void doStartMousePolling(); |
142 | /** |
143 | * Called from @link stopMousePolling when the mouse polling gets deactivated. Base implementation |
144 | * does nothing, inheriting classes can overwrite to e.g. stop a timer. |
145 | **/ |
146 | virtual void doStopMousePolling(); |
147 | /** |
148 | * Called from @link startCursorTracking when cursor image tracking gets activated. Inheriting class needs |
149 | * to overwrite to enable platform specific code for the tracking. |
150 | */ |
151 | virtual void doStartCursorTracking(); |
152 | /** |
153 | * Called from @link stopCursorTracking when cursor image tracking gets deactivated. Inheriting class needs |
154 | * to overwrite to disable platform specific code for the tracking. |
155 | */ |
156 | virtual void doStopCursorTracking(); |
157 | /** |
158 | * Provides the actual internal cursor position to inheriting classes. If an inheriting class needs |
159 | * access to the cursor position this method should be used instead of the static @link pos, as |
160 | * the static method syncs with the underlying system's cursor. |
161 | **/ |
162 | const QPoint ¤tPos() const; |
163 | /** |
164 | * Updates the internal position to @p pos without warping the pointer as |
165 | * @link setPos does. |
166 | **/ |
167 | void updatePos(const QPoint &pos); |
168 | void updatePos(int x, int y); |
169 | |
170 | private: |
171 | QPoint m_pos; |
172 | int m_mousePollingCounter; |
173 | int m_cursorTrackingCounter; |
174 | |
175 | KWIN_SINGLETON(Cursor) |
176 | }; |
177 | |
178 | class X11Cursor : public Cursor |
179 | { |
180 | Q_OBJECT |
181 | public: |
182 | virtual ~X11Cursor(); |
183 | protected: |
184 | virtual xcb_cursor_t getX11Cursor(Qt::CursorShape shape); |
185 | virtual void doSetPos(); |
186 | virtual void doGetPos(); |
187 | virtual void doStartMousePolling(); |
188 | virtual void doStopMousePolling(); |
189 | virtual void doStartCursorTracking(); |
190 | virtual void doStopCursorTracking(); |
191 | |
192 | private slots: |
193 | /** |
194 | * Because of QTimer's and the impossibility to get events for all mouse |
195 | * movements (at least I haven't figured out how) the position needs |
196 | * to be also refetched after each return to the event loop. |
197 | */ |
198 | void resetTimeStamp(); |
199 | void mousePolled(); |
200 | private: |
201 | X11Cursor(QObject *parent); |
202 | xcb_cursor_t createCursor(Qt::CursorShape shape); |
203 | QByteArray cursorName(Qt::CursorShape shape) const; |
204 | QHash<Qt::CursorShape, xcb_cursor_t > m_cursors; |
205 | xcb_timestamp_t m_timeStamp; |
206 | uint16_t m_buttonMask; |
207 | QTimer *m_resetTimeStampTimer; |
208 | QTimer *m_mousePollingTimer; |
209 | friend class Cursor; |
210 | }; |
211 | |
212 | inline const QPoint &Cursor::currentPos() const |
213 | { |
214 | return m_pos; |
215 | } |
216 | |
217 | inline void Cursor::updatePos(int x, int y) |
218 | { |
219 | updatePos(QPoint(x, y)); |
220 | } |
221 | |
222 | } |
223 | |
224 | #endif // KWIN_CURSOR_H |
225 | |