Support for cursor change tracking in KWin::Cursor

KWin::Cursor can track changes to the cursor image. It supports a
start/stop tracking to not handle these events if nobody is interested in
them. When enabled and the cursor image changes a signal is emitted with
the serial number of the new cursor image.

To track cursor image changes xcb_xfixes_select_cursor_input is used (see
XFixes Version 5.0 protocol, section 7).

This could be useful for the zoom effect when it replaces the cursor.

REVIEW: 110519
icc-effect-5.14.5
Martin Gräßlin 2013-05-19 09:32:27 +02:00
parent 17e38f3357
commit 8b2a5f9936
6 changed files with 108 additions and 0 deletions

View File

@ -27,6 +27,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Xlib
#include <X11/Xcursor/Xcursor.h>
#include <fixx11h.h>
// xcb
#include <xcb/xfixes.h>
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();

View File

@ -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:
/**

View File

@ -54,6 +54,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kkeyserver.h>
#include <X11/extensions/shape.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xatom.h>
#include <QX11Info>
@ -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<XFixesCursorNotifyEvent*>(e)->cursor_serial);
}
break;
}

View File

@ -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}

View File

@ -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

View File

@ -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;