diff --git a/CMakeLists.txt b/CMakeLists.txt index 84797e5a60..b5b0385035 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,6 +94,7 @@ set(kwin_KDEINIT_SRCS dbusinterface.cpp client.cpp client_machine.cpp + cursor.cpp tabgroup.cpp focuschain.cpp placement.cpp diff --git a/composite.cpp b/composite.cpp index e6cb0d484e..5702ec01d2 100644 --- a/composite.cpp +++ b/composite.cpp @@ -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(); diff --git a/composite.h b/composite.h index 963e63a3d3..b05d1ac04c 100644 --- a/composite.h +++ b/composite.h @@ -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; diff --git a/cursor.cpp b/cursor.cpp new file mode 100644 index 0000000000..43217dfabb --- /dev/null +++ b/cursor.cpp @@ -0,0 +1,278 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 Martin Gräßlin + +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 . +*********************************************************************/ + +#include "cursor.h" +// kwin +#include +#include "utils.h" +// Qt +#include +// Xlib +#include +#include + +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 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::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 diff --git a/cursor.h b/cursor.h new file mode 100644 index 0000000000..9acf0b2fd1 --- /dev/null +++ b/cursor.h @@ -0,0 +1,183 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2013 Martin Gräßlin + +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 . +*********************************************************************/ +#ifndef KWIN_CURSOR_H +#define KWIN_CURSOR_H +// Qt +#include +#include +#include +// xcb +#include + +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 ¤tPos() 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 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 diff --git a/effects.cpp b/effects.cpp index 42b15d9a65..f93dd99275 100644 --- a/effects.cpp +++ b/effects.cpp @@ -24,6 +24,7 @@ along with this program. If not, see . #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(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) diff --git a/effects.h b/effects.h index 80a2915cac..9b26ecb48b 100644 --- a/effects.h +++ b/effects.h @@ -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(); diff --git a/manage.cpp b/manage.cpp index 23f1056463..509c7948fd 100644 --- a/manage.cpp +++ b/manage.cpp @@ -27,6 +27,7 @@ along with this program. If not, see . #include #include +#include "cursor.h" #include "notifications.h" #include #include "rules.h" @@ -656,7 +657,7 @@ void Client::embedClient(Window w, const XWindowAttributes& attr) 0, // back_pixmap 0, // border_pixel static_cast(attr.colormap), // colormap - static_cast(QCursor(Qt::ArrowCursor).handle()) // cursor + Cursor::x11Cursor(Qt::ArrowCursor) }; const uint32_t cw_mask = XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | diff --git a/screenedge.cpp b/screenedge.cpp index f75f6a6b53..cfcf7261bd 100644 --- a/screenedge.cpp +++ b/screenedge.cpp @@ -32,6 +32,7 @@ along with this program. If not, see . // 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 wins; diff --git a/screenedge.h b/screenedge.h index 76add9d3d3..fe3446f41f 100644 --- a/screenedge.h +++ b/screenedge.h @@ -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; }; diff --git a/utils.cpp b/utils.cpp index 1079043de1..8c657b002a 100644 --- a/utils.cpp +++ b/utils.cpp @@ -49,6 +49,7 @@ along with this program. If not, see . #include #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 diff --git a/workspace.cpp b/workspace.cpp index 05fe79602c..464fd00167 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -52,6 +52,7 @@ along with this program. If not, see . #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(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; diff --git a/workspace.h b/workspace.h index 0269c0328e..b5411278c8 100644 --- a/workspace.h +++ b/workspace.h @@ -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();