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.
icc-effect-5.14.5
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();