Replacement class for QCursor

With Qt5 QCursor does no longer provide ::handle() which was used to
set a cursor on a native XWindow for which we do not have a QWidget.

Also KWin has had for quite some time an optimized version to get the
cursor position without doing XQueryPointer each time ::pos() is called.

These two features are merged into a new class Cursor providing more or
less the same API as QCursor.

In addition the new class provides a facility to perform mouse polling
replacing the implementations in Compositor and ScreenEdges.

For more information about the new class see the documentation for the
new class in cursor.h.
This commit is contained in:
Martin Gräßlin 2013-02-19 11:25:46 +01:00
parent 9655c7b3cb
commit f12cf0efba
13 changed files with 485 additions and 135 deletions

View file

@ -94,6 +94,7 @@ set(kwin_KDEINIT_SRCS
dbusinterface.cpp
client.cpp
client_machine.cpp
cursor.cpp
tabgroup.cpp
focuschain.cpp
placement.cpp

View file

@ -90,7 +90,6 @@ Compositor::Compositor(QObject* workspace)
connect(&unredirectTimer, SIGNAL(timeout()), SLOT(delayedCheckUnredirect()));
connect(&compositeResetTimer, SIGNAL(timeout()), SLOT(restart()));
connect(workspace, SIGNAL(configChanged()), SLOT(slotConfigChanged()));
connect(&mousePollingTimer, SIGNAL(timeout()), SLOT(performMousePoll()));
unredirectTimer.setSingleShot(true);
compositeResetTimer.setSingleShot(true);
nextPaintReference.invalidate(); // Initialize the timer
@ -286,7 +285,6 @@ void Compositor::finish()
delete m_scene;
m_scene = NULL;
compositeTimer.stop();
mousePollingTimer.stop();
repaints_region = QRegion();
for (ClientList::ConstIterator it = Workspace::self()->clientList().constBegin();
it != Workspace::self()->clientList().constEnd();
@ -583,11 +581,6 @@ void Compositor::performCompositing()
scheduleRepaint();
}
void Compositor::performMousePoll()
{
Workspace::self()->checkCursorPos();
}
bool Compositor::windowRepaintsPending() const
{
foreach (Toplevel * c, Workspace::self()->clientList())
@ -649,16 +642,6 @@ void Compositor::setCompositeTimer()
compositeTimer.start(qMin(padding, 250u), this); // force 4fps minimum
}
void Compositor::startMousePolling()
{
mousePollingTimer.start(20); // 50Hz. TODO: How often do we really need to poll?
}
void Compositor::stopMousePolling()
{
mousePollingTimer.stop();
}
bool Compositor::isActive()
{
return !m_finishing && hasScene();

View file

@ -74,9 +74,6 @@ public:
void addRepaint(const QRect& r);
void addRepaint(const QRegion& r);
void addRepaint(int x, int y, int w, int h);
// Mouse polling
void startMousePolling();
void stopMousePolling();
/**
* Whether the Compositor is active. That is a Scene is present and the Compositor is
* not shutting down itself.
@ -281,7 +278,6 @@ private Q_SLOTS:
void restart();
void fallbackToXRenderCompositing();
void performCompositing();
void performMousePoll();
void delayedCheckUnredirect();
void slotConfigChanged();
void releaseCompositorSelection();
@ -309,7 +305,6 @@ private:
uint vBlankInterval, fpsInterval;
int m_xrrRefreshRate;
QElapsedTimer nextPaintReference;
QTimer mousePollingTimer;
QRegion repaints_region;
QTimer unredirectTimer;

278
cursor.cpp Normal file
View file

@ -0,0 +1,278 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "cursor.h"
// kwin
#include <kwinglobals.h>
#include "utils.h"
// Qt
#include <QTimer>
// Xlib
#include <X11/Xcursor/Xcursor.h>
#include <fixx11h.h>
namespace KWin
{
Cursor *Cursor::s_self = NULL;
Cursor::Cursor(QObject *parent)
: QObject(parent)
, m_mousePollingCounter(0)
{
}
Cursor::~Cursor()
{
s_self = NULL;
}
Cursor *Cursor::create(QObject *parent)
{
Q_ASSERT(!s_self);
s_self = new X11Cursor(parent);
return s_self;
}
QPoint Cursor::pos()
{
s_self->doGetPos();
return s_self->m_pos;
}
void Cursor::setPos(const QPoint &pos)
{
// first query the current pos to not warp to the already existing pos
if (pos == Cursor::pos()) {
return;
}
s_self->m_pos = pos;
s_self->doSetPos();
}
void Cursor::setPos(int x, int y)
{
Cursor::setPos(QPoint(x, y));
}
xcb_cursor_t Cursor::getX11Cursor(Qt::CursorShape shape)
{
Q_UNUSED(shape)
return XCB_CURSOR_NONE;
}
xcb_cursor_t Cursor::x11Cursor(Qt::CursorShape shape)
{
return s_self->getX11Cursor(shape);
}
void Cursor::doSetPos()
{
emit posChanged(m_pos);
}
void Cursor::doGetPos()
{
}
void Cursor::updatePos(const QPoint &pos)
{
if (m_pos == pos) {
return;
}
m_pos = pos;
emit posChanged(m_pos);
}
void Cursor::startMousePolling()
{
++m_mousePollingCounter;
if (m_mousePollingCounter == 1) {
doStartMousePolling();
}
}
void Cursor::stopMousePolling()
{
Q_ASSERT(m_mousePollingCounter > 0);
--m_mousePollingCounter;
if (m_mousePollingCounter == 0) {
doStopMousePolling();
}
}
void Cursor::doStartMousePolling()
{
}
void Cursor::doStopMousePolling()
{
}
X11Cursor::X11Cursor(QObject *parent)
: Cursor(parent)
, m_timeStamp(XCB_TIME_CURRENT_TIME)
, m_buttonMask(0)
, m_resetTimeStampTimer(new QTimer(this))
, m_mousePollingTimer(new QTimer(this))
{
m_resetTimeStampTimer->setSingleShot(true);
connect(m_resetTimeStampTimer, SIGNAL(timeout()), SLOT(resetTimeStamp()));
// TODO: How often do we really need to poll?
m_mousePollingTimer->setInterval(100);
connect(m_mousePollingTimer, SIGNAL(timeout()), SLOT(mousePolled()));
}
X11Cursor::~X11Cursor()
{
}
void X11Cursor::doSetPos()
{
const QPoint &pos = currentPos();
xcb_warp_pointer(connection(), XCB_WINDOW_NONE, rootWindow(), 0, 0, 0, 0, pos.x(), pos.y());
// call default implementation to emit signal
Cursor::doSetPos();
}
void X11Cursor::doGetPos()
{
if (m_timeStamp != XCB_TIME_CURRENT_TIME &&
m_timeStamp == QX11Info::appTime()) {
// time stamps did not change, no need to query again
return;
}
m_timeStamp = QX11Info::appTime();
ScopedCPointer<xcb_query_pointer_reply_t> pointer(xcb_query_pointer_reply(connection(),
xcb_query_pointer_unchecked(connection(), rootWindow()), NULL));
if (!pointer) {
return;
}
m_buttonMask = pointer->mask;
updatePos(pointer->root_x, pointer->root_y);
m_resetTimeStampTimer->start(0);
}
void X11Cursor::resetTimeStamp()
{
m_timeStamp = XCB_TIME_CURRENT_TIME;
}
void X11Cursor::doStartMousePolling()
{
m_mousePollingTimer->start();
}
void X11Cursor::doStopMousePolling()
{
m_mousePollingTimer->stop();
}
void X11Cursor::mousePolled()
{
const QPoint last = currentPos();
const uint16_t lastMask = m_buttonMask;
doGetPos(); // Update if needed
if (last != currentPos() || lastMask != m_buttonMask) {
emit mouseChanged(currentPos(), last,
x11ToQtMouseButtons(m_buttonMask), x11ToQtMouseButtons(lastMask),
x11ToQtKeyboardModifiers(m_buttonMask), x11ToQtKeyboardModifiers(lastMask));
}
}
xcb_cursor_t X11Cursor::getX11Cursor(Qt::CursorShape shape)
{
QHash<Qt::CursorShape, xcb_cursor_t>::const_iterator it = m_cursors.constFind(shape);
if (it != m_cursors.constEnd()) {
return it.value();
}
return createCursor(shape);
}
xcb_cursor_t X11Cursor::createCursor(Qt::CursorShape shape)
{
const QByteArray name = cursorName(shape);
if (name.isEmpty()) {
return XCB_CURSOR_NONE;
}
// XCursor is an XLib only lib
const char *theme = XcursorGetTheme(display());
const int size = XcursorGetDefaultSize(display());
XcursorImage *ximg = XcursorLibraryLoadImage(name.constData(), theme, size);
if (!ximg) {
return XCB_CURSOR_NONE;
}
xcb_cursor_t cursor = XcursorImageLoadCursor(display(), ximg);
XcursorImageDestroy(ximg);
m_cursors.insert(shape, cursor);
return cursor;
}
QByteArray X11Cursor::cursorName(Qt::CursorShape shape) const
{
switch (shape) {
case Qt::ArrowCursor:
return QByteArray("left_ptr");
case Qt::UpArrowCursor:
return QByteArray("up_arrow");
case Qt::CrossCursor:
return QByteArray("cross");
case Qt::WaitCursor:
return QByteArray("wait");
case Qt::IBeamCursor:
return QByteArray("ibeam");
case Qt::SizeVerCursor:
return QByteArray("size_ver");
case Qt::SizeHorCursor:
return QByteArray("size_hor");
case Qt::SizeBDiagCursor:
return QByteArray("size_bdiag");
case Qt::SizeFDiagCursor:
return QByteArray("size_fdiag");
case Qt::SizeAllCursor:
return QByteArray("size_all");
case Qt::SplitVCursor:
return QByteArray("split_v");
case Qt::SplitHCursor:
return QByteArray("split_h");
case Qt::PointingHandCursor:
return QByteArray("pointing_hand");
case Qt::ForbiddenCursor:
return QByteArray("forbidden");
case Qt::OpenHandCursor:
return QByteArray("openhand");
case Qt::ClosedHandCursor:
return QByteArray("closedhand");
case Qt::WhatsThisCursor:
return QByteArray("whats_this");
case Qt::BusyCursor:
return QByteArray("left_ptr_watch");
case Qt::DragMoveCursor:
return QByteArray("dnd-move");
case Qt::DragCopyCursor:
return QByteArray("dnd-copy");
case Qt::DragLinkCursor:
return QByteArray("dnd-link");
default:
return QByteArray();
}
}
} // namespace

183
cursor.h Normal file
View file

@ -0,0 +1,183 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_CURSOR_H
#define KWIN_CURSOR_H
// Qt
#include <QHash>
#include <QObject>
#include <QPoint>
// xcb
#include <xcb/xcb.h>
class QTimer;
namespace KWin
{
/**
* @short Replacement for QCursor.
*
* This class provides a similar API to QCursor and should be preferred inside KWin. It allows to
* get the position and warp the mouse cursor with static methods just like QCursor. It also provides
* the possibility to get an X11 cursor for a Qt::CursorShape - a functionality lost in Qt 5's QCursor
* implementation.
*
* In addition the class provides a mouse polling facility as required by e.g. Effects and ScreenEdges
* and emits signals when the mouse position changes. In opposite to QCursor this class is a QObject
* and cannot be constructed. Instead it provides a singleton getter, though the most important
* methods are wrapped in a static method, just like QCursor.
*
* The actual implementation is split into two parts: a system independent interface and a windowing
* system specific subclass. So far only an X11 backend is implemented which uses query pointer to
* fetch the position and warp pointer to set the position. It uses a timer based mouse polling and
* can provide X11 cursors through the XCursor library.
**/
class Cursor : public QObject
{
Q_OBJECT
public:
virtual ~Cursor();
void startMousePolling();
void stopMousePolling();
/**
* Returns the current cursor position. This method does an update of the mouse position if
* needed. It's save to call it multiple times.
*
* Implementing subclasses should prefer to use @link currentPos which is not performing a check
* for update.
**/
static QPoint pos();
/**
* Warps the mouse cursor to new @p pos.
**/
static void setPos(const QPoint &pos);
static void setPos(int x, int y);
static Cursor *self();
static xcb_cursor_t x11Cursor(Qt::CursorShape shape);
/**
* @internal
* Factory method
**/
static Cursor *create(QObject *parent);
Q_SIGNALS:
void posChanged(QPoint pos);
void mouseChanged(const QPoint& pos, const QPoint& oldpos,
Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons,
Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers);
protected:
Cursor(QObject *parent);
/**
* Called from @link x11Cursor to actually retrieve the X11 cursor. Base implementation returns
* a null cursor, an implementing subclass should implement this method if it can provide X11
* mouse cursors.
**/
virtual xcb_cursor_t getX11Cursor(Qt::CursorShape shape);
/**
* Performs the actual warping of the cursor.
**/
virtual void doSetPos();
/**
* Called from @link pos() to allow syncing the internal position with the underlying
* system's cursor position.
**/
virtual void doGetPos();
/**
* Called from @link startMousePolling when the mouse polling gets activated. Base implementation
* does nothing, inheriting classes can overwrite to e.g. start a timer.
**/
virtual void doStartMousePolling();
/**
* Called from @link stopMousePolling when the mouse polling gets deactivated. Base implementation
* does nothing, inheriting classes can overwrite to e.g. stop a timer.
**/
virtual void doStopMousePolling();
/**
* 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
* the static method syncs with the underlying system's cursor.
**/
const QPoint &currentPos() const;
/**
* Updates the internal position to @p pos without warping the pointer as
* @link setPos does.
**/
void updatePos(const QPoint &pos);
void updatePos(int x, int y);
private:
QPoint m_pos;
int m_mousePollingCounter;
static Cursor *s_self;
};
class X11Cursor : public Cursor
{
Q_OBJECT
public:
virtual ~X11Cursor();
protected:
virtual xcb_cursor_t getX11Cursor(Qt::CursorShape shape);
virtual void doSetPos();
virtual void doGetPos();
virtual void doStartMousePolling();
virtual void doStopMousePolling();
private slots:
/**
* Because of QTimer's and the impossibility to get events for all mouse
* movements (at least I haven't figured out how) the position needs
* to be also refetched after each return to the event loop.
*/
void resetTimeStamp();
void mousePolled();
private:
X11Cursor(QObject *parent);
xcb_cursor_t createCursor(Qt::CursorShape shape);
QByteArray cursorName(Qt::CursorShape shape) const;
QHash<Qt::CursorShape, xcb_cursor_t > m_cursors;
xcb_timestamp_t m_timeStamp;
uint16_t m_buttonMask;
QTimer *m_resetTimeStampTimer;
QTimer *m_mousePollingTimer;
friend class Cursor;
};
inline Cursor *Cursor::self()
{
return s_self;
}
inline const QPoint &Cursor::currentPos() const
{
return m_pos;
}
inline void Cursor::updatePos(int x, int y)
{
updatePos(QPoint(x, y));
}
}
#endif // KWIN_CURSOR_H

View file

@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "effectsadaptor.h"
#include "deleted.h"
#include "client.h"
#include "cursor.h"
#include "group.h"
#include "scene_xrender.h"
#include "scene_opengl.h"
@ -205,7 +206,6 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
, keyboard_grab_effect(NULL)
, fullscreen_effect(0)
, next_window_quad_type(EFFECT_QUAD_TYPE_START)
, mouse_poll_ref_count(0)
, m_compositor(compositor)
, m_scene(scene)
, m_screenLockerWatcher(new ScreenLockerWatcher(this))
@ -225,7 +225,7 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
connect(ws, SIGNAL(clientActivated(KWin::Client*)), this, SLOT(slotClientActivated(KWin::Client*)));
connect(ws, SIGNAL(deletedRemoved(KWin::Deleted*)), this, SLOT(slotDeletedRemoved(KWin::Deleted*)));
connect(vds, SIGNAL(countChanged(uint,uint)), SIGNAL(numberDesktopsChanged(uint)));
connect(ws, SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)),
connect(Cursor::self(), SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)),
SIGNAL(mouseChanged(QPoint,QPoint,Qt::MouseButtons,Qt::MouseButtons,Qt::KeyboardModifiers,Qt::KeyboardModifiers)));
connect(ws, SIGNAL(propertyNotify(long)), this, SLOT(slotPropertyNotify(long)));
connect(ws, SIGNAL(activityAdded(QString)), SIGNAL(activityAdded(QString)));
@ -675,17 +675,12 @@ void* EffectsHandlerImpl::getProxy(QString name)
void EffectsHandlerImpl::startMousePolling()
{
if (!mouse_poll_ref_count) // Start timer if required
m_compositor->startMousePolling();
mouse_poll_ref_count++;
Cursor::self()->startMousePolling();
}
void EffectsHandlerImpl::stopMousePolling()
{
assert(mouse_poll_ref_count);
mouse_poll_ref_count--;
if (!mouse_poll_ref_count) // Stop timer if required
m_compositor->stopMousePolling();
Cursor::self()->stopMousePolling();
}
bool EffectsHandlerImpl::hasKeyboardGrab() const
@ -1161,7 +1156,7 @@ xcb_window_t EffectsHandlerImpl::createInputWindow(Effect* e, int x, int y, int
const uint32_t values[] = {
true,
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION,
static_cast<uint32_t>(cursor.handle())
Cursor::x11Cursor(cursor.shape())
};
xcb_create_window(connection(), 0, win, rootWindow(), x, y, w, h, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
XCB_COPY_FROM_PARENT, mask, values);
@ -1276,7 +1271,7 @@ void EffectsHandlerImpl::checkInputWindowStacking()
QPoint EffectsHandlerImpl::cursorPos() const
{
return Workspace::self()->cursorPos();
return Cursor::pos();
}
void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border, Effect *effect)

View file

@ -227,7 +227,6 @@ protected:
QMultiMap< int, EffectPair > effect_order;
QHash< long, int > registered_atoms;
int next_window_quad_type;
int mouse_poll_ref_count;
private Q_SLOTS:
void slotEffectsQueried();

View file

@ -27,6 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kglobal.h>
#include <X11/extensions/shape.h>
#include "cursor.h"
#include "notifications.h"
#include <QX11Info>
#include "rules.h"
@ -656,7 +657,7 @@ void Client::embedClient(Window w, const XWindowAttributes& attr)
0, // back_pixmap
0, // border_pixel
static_cast<uint32_t>(attr.colormap), // colormap
static_cast<uint32_t>(QCursor(Qt::ArrowCursor).handle()) // cursor
Cursor::x11Cursor(Qt::ArrowCursor)
};
const uint32_t cw_mask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL |

View file

@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// KWin
#include "atoms.h"
#include "client.h"
#include "cursor.h"
#include "effects.h"
#include "utils.h"
#include "workspace.h"
@ -255,7 +256,7 @@ void Edge::switchDesktop(const QPoint &cursorPos)
}
vds->setCurrent(desktop);
if (vds->current() != oldDesktop) {
QCursor::setPos(pos);
Cursor::setPos(pos);
}
}
@ -276,7 +277,7 @@ void Edge::pushCursorBack(const QPoint &cursorPos)
if (isBottom()) {
y -= distance.height();
}
QCursor::setPos(x, y);
Cursor::setPos(x, y);
}
void Edge::setGeometry(const QRect &geometry)
@ -503,14 +504,16 @@ void WindowBasedEdge::doGeometryUpdate()
void WindowBasedEdge::doStartApproaching()
{
m_approachWindow.unmap();
connect(edges(), SIGNAL(mousePollingTimerEvent(QPoint)), SLOT(updateApproaching(QPoint)));
edges()->startMousePolling();
Cursor *cursor = Cursor::self();
connect(cursor, SIGNAL(posChanged(QPoint)), SLOT(updateApproaching(QPoint)));
cursor->startMousePolling();
}
void WindowBasedEdge::doStopApproaching()
{
disconnect(edges(), SIGNAL(mousePollingTimerEvent(QPoint)), this, SLOT(updateApproaching(QPoint)));
edges()->stopMousePolling();
Cursor *cursor = Cursor::self();
disconnect(cursor, SIGNAL(posChanged(QPoint)), this, SLOT(updateApproaching(QPoint)));
cursor->stopMousePolling();
m_approachWindow.map();
}
@ -555,10 +558,7 @@ ScreenEdges::ScreenEdges(QObject *parent)
, m_actionBottom(ElectricActionNone)
, m_actionBottomLeft(ElectricActionNone)
, m_actionLeft(ElectricActionNone)
, m_mousePolling(0)
, m_mousePollingTimer(new QTimer(this))
{
connect(m_mousePollingTimer, SIGNAL(timeout()), SLOT(performMousePoll()));
}
ScreenEdges::~ScreenEdges()
@ -1047,28 +1047,6 @@ void ScreenEdges::ensureOnTop()
Xcb::restackWindowsWithRaise(windows());
}
void ScreenEdges::startMousePolling()
{
m_mousePolling++;
if (m_mousePolling == 1) {
m_mousePollingTimer->start(100); // TODO: How often do we really need to poll?
}
}
void ScreenEdges::stopMousePolling()
{
m_mousePolling--;
if (m_mousePolling == 0) {
m_mousePollingTimer->stop();
}
}
void ScreenEdges::performMousePoll()
{
Workspace::self()->checkCursorPos();
emit mousePollingTimerEvent(Workspace::self()->cursorPos());
}
QVector< xcb_window_t > ScreenEdges::windows() const
{
QVector<xcb_window_t> wins;

View file

@ -282,8 +282,6 @@ public:
ElectricBorderAction actionBottom() const;
ElectricBorderAction actionBottomLeft() const;
ElectricBorderAction actionLeft() const;
void startMousePolling();
void stopMousePolling();
/**
* Singleton getter for this manager.
@ -317,12 +315,8 @@ Q_SIGNALS:
* @c 0.0 meaning far away from the border, @c 1.0 in trigger distance.
**/
void approaching(ElectricBorder border, qreal factor, const QRect &geometry);
void mousePollingTimerEvent(QPoint cursorPos);
void checkBlocking();
private Q_SLOTS:
void performMousePoll();
private:
enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 };
void setDesktopSwitching(bool enable);
@ -353,8 +347,6 @@ private:
ElectricBorderAction m_actionBottom;
ElectricBorderAction m_actionBottomLeft;
ElectricBorderAction m_actionLeft;
int m_mousePolling;
QTimer *m_mousePollingTimer;
static ScreenEdges *s_self;
};

View file

@ -49,6 +49,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include "atoms.h"
#include "cursor.h"
#include "notifications.h"
#include "workspace.h"
@ -325,7 +326,7 @@ void ungrabXKeyboard()
QPoint cursorPos()
{
return Workspace::self()->cursorPos();
return Cursor::self()->pos();
}
// converting between X11 mouse/keyboard state mask and Qt button/keyboard states

View file

@ -52,6 +52,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "tabbox.h"
#endif
#include "atoms.h"
#include "cursor.h"
#include "placement.h"
#include "notifications.h"
#include "outline.h"
@ -159,6 +160,9 @@ Workspace::Workspace(bool restore)
Extensions::init();
Xcb::Extensions::self();
// start the cursor support
Cursor::create(this);
// PluginMgr needs access to the config file, so we need to wait for it for finishing
reparseConfigFuture.waitForFinished();
options->loadConfig();
@ -1829,60 +1833,6 @@ void Workspace::slotBlockShortcuts(int data)
(*it)->updateMouseGrab();
}
// Optimized version of QCursor::pos() that tries to avoid X roundtrips
// by updating the value only when the X timestamp changes.
static QPoint last_cursor_pos;
static int last_buttons = 0;
static Time last_cursor_timestamp = CurrentTime;
static QTimer* last_cursor_timer;
QPoint Workspace::cursorPos() const
{
if (last_cursor_timestamp == CurrentTime ||
last_cursor_timestamp != QX11Info::appTime()) {
last_cursor_timestamp = QX11Info::appTime();
Window root;
Window child;
int root_x, root_y, win_x, win_y;
uint state;
XQueryPointer(display(), rootWindow(), &root, &child,
&root_x, &root_y, &win_x, &win_y, &state);
last_cursor_pos = QPoint(root_x, root_y);
last_buttons = state;
if (last_cursor_timer == NULL) {
Workspace* ws = const_cast<Workspace*>(this);
last_cursor_timer = new QTimer(ws);
last_cursor_timer->setSingleShot(true);
connect(last_cursor_timer, SIGNAL(timeout()), ws, SLOT(resetCursorPosTime()));
}
last_cursor_timer->start(0);
}
return last_cursor_pos;
}
/**
* Because of QTimer's and the impossibility to get events for all mouse
* movements (at least I haven't figured out how) the position needs
* to be also refetched after each return to the event loop.
*/
void Workspace::resetCursorPosTime()
{
last_cursor_timestamp = CurrentTime;
}
void Workspace::checkCursorPos()
{
QPoint last = last_cursor_pos;
int lastb = last_buttons;
cursorPos(); // Update if needed
if (last != last_cursor_pos || lastb != last_buttons) {
emit mouseChanged(last_cursor_pos, last,
x11ToQtMouseButtons(last_buttons), x11ToQtMouseButtons(lastb),
x11ToQtKeyboardModifiers(last_buttons), x11ToQtKeyboardModifiers(lastb));
}
}
Outline* Workspace::outline()
{
return m_outline;

View file

@ -379,8 +379,6 @@ public:
bool globalShortcutsDisabled() const;
void disableGlobalShortcuts(bool disable);
void disableGlobalShortcutsForClient(bool disable);
QPoint cursorPos() const;
void checkCursorPos();
void sessionSaveStarted();
void sessionSaveDone();
@ -505,7 +503,6 @@ private slots:
void slotMenuHidden(qulonglong wid);
void slotClearMenus();
#endif
void resetCursorPosTime();
void updateCurrentActivity(const QString &new_activity);
void slotActivityRemoved(const QString &activity);
void slotActivityAdded(const QString &activity);
@ -534,9 +531,6 @@ signals:
void groupAdded(KWin::Group*);
void unmanagedAdded(KWin::Unmanaged*);
void deletedRemoved(KWin::Deleted*);
void mouseChanged(const QPoint& pos, const QPoint& oldpos,
Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons,
Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers);
void propertyNotify(long a);
void configChanged();
void reinitializeCompositing();