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;