diff --git a/cursor.cpp b/cursor.cpp index 35a0365c81..8ec8511e2e 100644 --- a/cursor.cpp +++ b/cursor.cpp @@ -27,6 +27,8 @@ along with this program. If not, see . // Xlib #include #include +// xcb +#include namespace KWin { @@ -36,6 +38,7 @@ KWIN_SINGLETON_FACTORY_FACTORED(Cursor, X11Cursor) Cursor::Cursor(QObject *parent) : QObject(parent) , m_mousePollingCounter(0) + , m_cursorTrackingCounter(0) { } @@ -119,6 +122,40 @@ void Cursor::doStopMousePolling() { } +void Cursor::startCursorTracking() +{ + ++m_cursorTrackingCounter; + if (m_cursorTrackingCounter == 1) { + doStartCursorTracking(); + } +} + +void Cursor::stopCursorTracking() +{ + Q_ASSERT(m_cursorTrackingCounter > 0); + --m_cursorTrackingCounter; + if (m_cursorTrackingCounter == 0) { + doStopCursorTracking(); + } +} + +void Cursor::doStartCursorTracking() +{ +} + +void Cursor::doStopCursorTracking() +{ +} + +void Cursor::notifyCursorChanged(uint32_t serial) +{ + if (m_cursorTrackingCounter <= 0) { + // cursor change tracking is currently disabled, so don't emit signal + return; + } + emit cursorChanged(serial); +} + X11Cursor::X11Cursor(QObject *parent) : Cursor(parent) , m_timeStamp(XCB_TIME_CURRENT_TIME) @@ -178,6 +215,16 @@ void X11Cursor::doStopMousePolling() m_mousePollingTimer->stop(); } +void X11Cursor::doStartCursorTracking() +{ + xcb_xfixes_select_cursor_input(connection(), rootWindow(), XCB_XFIXES_CURSOR_NOTIFY_MASK_DISPLAY_CURSOR); +} + +void X11Cursor::doStopCursorTracking() +{ + xcb_xfixes_select_cursor_input(connection(), rootWindow(), 0); +} + void X11Cursor::mousePolled() { const QPoint last = currentPos(); diff --git a/cursor.h b/cursor.h index 6fb0ad9698..b1d91061af 100644 --- a/cursor.h +++ b/cursor.h @@ -58,6 +58,34 @@ public: virtual ~Cursor(); void startMousePolling(); void stopMousePolling(); + /** + * @brief Enables tracking changes of cursor images. + * + * After enabling cursor change tracking the signal @link cursorChanged will be emitted + * whenever a change to the cursor image is recognized. + * + * Use @link stopCursorTracking to no longer emit this signal. Note: the signal will be + * emitted until each call of this method has been matched with a call to stopCursorTracking. + * + * This tracking is not about pointer position tracking. + * @see stopCursorTracking + * @see cursorChanged + */ + void startCursorTracking(); + /** + * @brief Disables tracking changes of cursor images. + * + * Only call after using @link startCursorTracking. + * + * @see startCursorTracking + */ + void stopCursorTracking(); + /** + * @internal + * + * Called from X11 event handler. + */ + void notifyCursorChanged(uint32_t serial); /** * Returns the current cursor position. This method does an update of the mouse position if @@ -79,6 +107,16 @@ Q_SIGNALS: void mouseChanged(const QPoint& pos, const QPoint& oldpos, Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers); + /** + * @brief Signal emitted when the cursor image changes. + * + * To enable these signals use @link startCursorTracking. + * + * @param serial The serial number of the new selected cursor. + * @see startCursorTracking + * @see stopCursorTracking + */ + void cursorChanged(uint32_t serial); protected: /** @@ -106,6 +144,16 @@ protected: * does nothing, inheriting classes can overwrite to e.g. stop a timer. **/ virtual void doStopMousePolling(); + /** + * Called from @link startCursorTracking when cursor image tracking gets activated. Inheriting class needs + * to overwrite to enable platform specific code for the tracking. + */ + virtual void doStartCursorTracking(); + /** + * Called from @link stopCursorTracking when cursor image tracking gets deactivated. Inheriting class needs + * to overwrite to disable platform specific code for the tracking. + */ + virtual void doStopCursorTracking(); /** * Provides the actual internal cursor position to inheriting classes. If an inheriting class needs * access to the cursor position this method should be used instead of the static @link pos, as @@ -122,6 +170,7 @@ protected: private: QPoint m_pos; int m_mousePollingCounter; + int m_cursorTrackingCounter; KWIN_SINGLETON(Cursor) }; @@ -137,6 +186,8 @@ protected: virtual void doGetPos(); virtual void doStartMousePolling(); virtual void doStopMousePolling(); + virtual void doStartCursorTracking(); + virtual void doStopCursorTracking(); private slots: /** diff --git a/events.cpp b/events.cpp index fda07e75a5..1cb3a38e9b 100644 --- a/events.cpp +++ b/events.cpp @@ -54,6 +54,7 @@ along with this program. If not, see . #include #include +#include #include #include #include @@ -343,6 +344,8 @@ bool Workspace::workspaceEvent(XEvent * e) foreach (Client * c, desktops) c->syncEvent(reinterpret_cast< XSyncAlarmNotifyEvent* >(e)); #endif + } else if (e->type == Xcb::Extensions::self()->fixesCursorNotifyEvent() && Xcb::Extensions::self()->isFixesAvailable()) { + Cursor::self()->notifyCursorChanged(reinterpret_cast(e)->cursor_serial); } break; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 781dae5e52..56f3859ecf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -51,6 +51,7 @@ target_link_libraries( testClientMachine ${QT_QTCORE_LIBRARY} ${KDE4_KDEUI_LIBS} ${XCB_XCB_LIBRARIES} + ${XCB_XFIXES_LIBRARIES} ${X11_XCB_LIBRARIES} ${X11_X11_LIB} # to make jenkins happy ${X11_Xcursor_LIB} diff --git a/xcbutils.cpp b/xcbutils.cpp index 525a6803b0..54a09e33c7 100644 --- a/xcbutils.cpp +++ b/xcbutils.cpp @@ -215,6 +215,11 @@ bool Extensions::isFixesRegionAvailable() const return m_fixes.version >= 0x30; // 3 } +int Extensions::fixesCursorNotifyEvent() const +{ + return m_fixes.eventBase + XCB_XFIXES_CURSOR_NOTIFY; +} + bool Extensions::isShapeInputAvailable() const { return m_shape.version >= 0x11; // 1.1 diff --git a/xcbutils.h b/xcbutils.h index a5609cb7d7..b09a126b24 100644 --- a/xcbutils.h +++ b/xcbutils.h @@ -245,6 +245,7 @@ public: bool isFixesAvailable() const { return m_fixes.version > 0; } + int fixesCursorNotifyEvent() const; bool isFixesRegionAvailable() const; bool isSyncAvailable() const { return m_sync.present;