backends/x11/standalone: remove on-demand mouse polling

Instead, rely on XInput if available, and fall back to polling every 50ms if not
This commit is contained in:
Xaver Hugl 2024-04-18 15:40:40 +02:00
parent 20d5f9bc6e
commit 26b15feb61
17 changed files with 67 additions and 300 deletions

View file

@ -24,17 +24,24 @@ X11Cursor::X11Cursor(bool xInputSupport)
, m_timeStamp(XCB_TIME_CURRENT_TIME)
, m_buttonMask(0)
, m_hasXInput(xInputSupport)
, m_needsPoll(false)
{
Cursors::self()->setMouse(this);
m_resetTimeStampTimer.setSingleShot(true);
connect(&m_resetTimeStampTimer, &QTimer::timeout, this, &X11Cursor::resetTimeStamp);
// TODO: How often do we really need to poll?
m_mousePollingTimer.setInterval(50);
connect(&m_mousePollingTimer, &QTimer::timeout, this, &X11Cursor::mousePolled);
if (m_hasXInput) {
// with XInput we don't have to poll the mouse on a timer, Xorg will notify us when it moved
m_resetTimeStampTimer.setSingleShot(true);
m_mousePollingTimer.setSingleShot(true);
m_mousePollingTimer.setInterval(50);
connect(qApp->eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, this, &X11Cursor::aboutToBlock);
} else {
connect(&m_resetTimeStampTimer, &QTimer::timeout, this, &X11Cursor::resetTimeStamp);
connect(&m_mousePollingTimer, &QTimer::timeout, this, &X11Cursor::pollMouse);
m_resetTimeStampTimer.setSingleShot(true);
m_mousePollingTimer.setSingleShot(false);
m_mousePollingTimer.setInterval(50);
m_mousePollingTimer.start();
}
if (Xcb::Extensions::self()->isFixesAvailable()) {
xcb_xfixes_select_cursor_input(connection(), rootWindow(), XCB_XFIXES_CURSOR_NOTIFY_MASK_DISPLAY_CURSOR);
}
#ifndef KCMRULES
@ -81,37 +88,12 @@ void X11Cursor::resetTimeStamp()
void X11Cursor::aboutToBlock()
{
if (m_needsPoll) {
mousePolled();
m_needsPoll = false;
}
}
void X11Cursor::doStartMousePolling()
{
if (!m_hasXInput) {
if (!m_mousePollingTimer.isActive()) {
m_mousePollingTimer.start();
}
}
void X11Cursor::doStopMousePolling()
{
if (!m_hasXInput) {
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()
void X11Cursor::pollMouse()
{
static QPointF lastPos = currentPos();
static uint16_t lastMask = m_buttonMask;
@ -127,13 +109,13 @@ void X11Cursor::mousePolled()
void X11Cursor::notifyCursorChanged()
{
if (!isCursorTracking()) {
// cursor change tracking is currently disabled, so don't emit signal
return;
}
Q_EMIT cursorChanged();
}
void X11Cursor::notifyCursorPosChanged()
{
pollMouse();
}
}
#include "moc_x11_standalone_cursor.cpp"

View file

@ -23,25 +23,20 @@ public:
X11Cursor(bool xInputSupport = false);
~X11Cursor() override;
void schedulePoll()
{
m_needsPoll = true;
}
/**
* @internal
*
* Called from X11 event handler.
*/
void notifyCursorChanged();
/**
* @internal queries the cursor position
*/
void notifyCursorPosChanged();
protected:
void doSetPos() override;
void doGetPos() override;
void doStartMousePolling() override;
void doStopMousePolling() override;
void doStartCursorTracking() override;
void doStopCursorTracking() override;
private Q_SLOTS:
/**
@ -50,8 +45,8 @@ private Q_SLOTS:
* to be also refetched after each return to the event loop.
*/
void resetTimeStamp();
void mousePolled();
void aboutToBlock();
void pollMouse();
private:
xcb_timestamp_t m_timeStamp;
@ -59,7 +54,6 @@ private:
QTimer m_resetTimeStampTimer;
QTimer m_mousePollingTimer;
bool m_hasXInput;
bool m_needsPoll;
std::unique_ptr<XFixesCursorEventFilter> m_xfixesFilter;

View file

@ -98,7 +98,6 @@ void WindowBasedEdge::doStartApproaching()
m_approachWindow.unmap();
Cursor *cursor = Cursors::self()->mouse();
m_cursorPollingConnection = connect(cursor, &Cursor::posChanged, this, &WindowBasedEdge::updateApproaching);
cursor->startMousePolling();
}
void WindowBasedEdge::doStopApproaching()
@ -108,7 +107,6 @@ void WindowBasedEdge::doStopApproaching()
}
disconnect(m_cursorPollingConnection);
m_cursorPollingConnection = QMetaObject::Connection();
Cursors::self()->mouse()->stopMousePolling();
m_approachWindow.map();
}

View file

@ -80,11 +80,7 @@ public:
break;
// TODO: further buttons, horizontal scrolling?
}
}
if (m_x11Cursor) {
m_x11Cursor->schedulePoll();
}
break;
} break;
case XI_RawButtonRelease: {
auto e = reinterpret_cast<xXIRawEvent *>(event);
switch (e->detail) {
@ -107,11 +103,12 @@ public:
break;
// TODO: further buttons, horizontal scrolling?
}
}
} break;
case XI_RawMotion: {
if (m_x11Cursor) {
m_x11Cursor->schedulePoll();
m_x11Cursor->notifyCursorPosChanged();
}
break;
} break;
case XI_TouchBegin: {
auto e = reinterpret_cast<xXIDeviceEvent *>(event);
m_lastTouchPositions.insert(e->detail, QPointF(fixed1616ToReal(e->event_x), fixed1616ToReal(e->event_y)));
@ -150,9 +147,6 @@ public:
break;
}
default:
if (m_x11Cursor) {
m_x11Cursor->schedulePoll();
}
break;
}
return false;

View file

@ -113,9 +113,7 @@ void Cursors::emitCurrentCursorChanged()
}
Cursor::Cursor()
: m_mousePollingCounter(0)
, m_cursorTrackingCounter(0)
, m_themeName(defaultThemeName())
: m_themeName(defaultThemeName())
, m_themeSize(defaultThemeSize())
{
loadThemeSettings();
@ -285,56 +283,6 @@ void Cursor::updatePos(const QPointF &pos)
Q_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()
{
}
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()
{
}
QString Cursor::defaultThemeName()
{
return QStringLiteral("default");

View file

@ -104,30 +104,6 @@ class KWIN_EXPORT Cursor : public QObject
public:
Cursor();
~Cursor() override;
void startMousePolling();
void stopMousePolling();
/**
* @brief Enables tracking changes of cursor images.
*
* After enabling cursor change tracking the signal cursorChanged will be emitted
* whenever a change to the cursor image is recognized.
*
* Use 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 startCursorTracking.
*
* @see startCursorTracking
*/
void stopCursorTracking();
/**
* @brief The name of the currently used Cursor theme.
@ -214,27 +190,6 @@ protected:
* system's cursor position.
*/
virtual void doGetPos();
/**
* Called from 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 stopMousePolling when the mouse polling gets deactivated. Base implementation
* does nothing, inheriting classes can overwrite to e.g. stop a timer.
*/
virtual void doStopMousePolling();
/**
* Called from 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 stopCursorTracking when cursor image tracking gets deactivated. Inheriting class needs
* to overwrite to disable platform specific code for the tracking.
*/
virtual void doStopCursorTracking();
bool isCursorTracking() const;
/**
* 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 @ref pos, as
@ -257,8 +212,6 @@ private:
CursorSource *m_source = nullptr;
QHash<QByteArray, xcb_cursor_t> m_cursors;
QPointF m_pos;
int m_mousePollingCounter;
int m_cursorTrackingCounter;
QString m_themeName;
int m_themeSize;
};
@ -327,12 +280,6 @@ inline int Cursor::themeSize() const
{
return m_themeSize;
}
inline bool Cursor::isCursorTracking() const
{
return m_cursorTrackingCounter > 0;
}
}
Q_DECLARE_METATYPE(KWin::CursorShape)

View file

@ -122,7 +122,6 @@ EffectsHandler::EffectsHandler(Compositor *compositor, WorkspaceScene *scene)
, m_compositor(compositor)
, m_scene(scene)
, m_effectLoader(new EffectLoader(this))
, m_trackingCursorChanges(0)
{
if (compositing_type == NoCompositing) {
return;
@ -239,6 +238,8 @@ EffectsHandler::EffectsHandler(Compositor *compositor, WorkspaceScene *scene)
connect(inputMethod, &InputMethod::panelChanged, this, &EffectsHandler::inputPanelChanged);
}
connect(Cursors::self()->mouse(), &Cursor::cursorChanged, this, &EffectsHandler::cursorShapeChanged);
reconfigure();
}
@ -635,20 +636,6 @@ void EffectsHandler::registerTouchscreenSwipeShortcut(SwipeDirection direction,
input()->registerTouchscreenSwipeShortcut(direction, fingerCount, action, progressCallback);
}
void EffectsHandler::startMousePolling()
{
if (Cursors::self()->mouse()) {
Cursors::self()->mouse()->startMousePolling();
}
}
void EffectsHandler::stopMousePolling()
{
if (Cursors::self()->mouse()) {
Cursors::self()->mouse()->stopMousePolling();
}
}
bool EffectsHandler::hasKeyboardGrab() const
{
return keyboard_grab_effect != nullptr;
@ -1082,30 +1069,6 @@ bool EffectsHandler::checkInputWindowEvent(QWheelEvent *e)
return true;
}
void EffectsHandler::connectNotify(const QMetaMethod &signal)
{
if (signal == QMetaMethod::fromSignal(&EffectsHandler::cursorShapeChanged)) {
if (!m_trackingCursorChanges) {
connect(Cursors::self()->mouse(), &Cursor::cursorChanged, this, &EffectsHandler::cursorShapeChanged);
Cursors::self()->mouse()->startCursorTracking();
}
++m_trackingCursorChanges;
}
QObject::connectNotify(signal);
}
void EffectsHandler::disconnectNotify(const QMetaMethod &signal)
{
if (signal == QMetaMethod::fromSignal(&EffectsHandler::cursorShapeChanged)) {
Q_ASSERT(m_trackingCursorChanges > 0);
if (!--m_trackingCursorChanges) {
Cursors::self()->mouse()->stopCursorTracking();
disconnect(Cursors::self()->mouse(), &Cursor::cursorChanged, this, &EffectsHandler::cursorShapeChanged);
}
}
QObject::disconnectNotify(signal);
}
void EffectsHandler::checkInputWindowStacking()
{
if (m_grabbedMouseEffects.isEmpty()) {

View file

@ -253,10 +253,6 @@ public:
*/
void registerTouchscreenSwipeShortcut(SwipeDirection direction, uint fingerCount, QAction *action, std::function<void(qreal)> progressCallback);
// Mouse polling
void startMousePolling();
void stopMousePolling();
void reserveElectricBorder(ElectricBorder border, Effect *effect);
void unreserveElectricBorder(ElectricBorder border, Effect *effect);
@ -1065,8 +1061,6 @@ public Q_SLOTS:
Q_SCRIPTABLE QString debug(const QString &name, const QString &parameter = QString()) const;
protected:
void connectNotify(const QMetaMethod &signal) override;
void disconnectNotify(const QMetaMethod &signal) override;
void effectsChanged();
void setupWindowConnections(KWin::Window *window);
@ -1122,7 +1116,6 @@ protected:
WorkspaceScene *m_scene;
QList<Effect *> m_grabbedMouseEffects;
EffectLoader *m_effectLoader;
int m_trackingCursorChanges;
std::unique_ptr<WindowPropertyNotifyX11Filter> m_x11WindowPropertyNotify;
};

View file

@ -32,7 +32,6 @@ const int FRAME_WIDTH = 5;
MagnifierEffect::MagnifierEffect()
: m_zoom(1)
, m_targetZoom(1)
, m_polling(false)
, m_lastPresentTime(std::chrono::milliseconds::zero())
, m_texture(nullptr)
, m_fbo(nullptr)
@ -203,10 +202,6 @@ QRect MagnifierEffect::magnifierArea(QPointF pos) const
void MagnifierEffect::zoomIn()
{
m_targetZoom *= 1.2;
if (!m_polling) {
m_polling = true;
effects->startMousePolling();
}
if (effects->isOpenGLCompositing() && !m_texture) {
effects->makeOpenGLContextCurrent();
m_texture = GLTexture::allocate(GL_RGBA16F, m_magnifierSize);
@ -224,10 +219,6 @@ void MagnifierEffect::zoomOut()
m_targetZoom /= 1.2;
if (m_targetZoom <= 1) {
m_targetZoom = 1;
if (m_polling) {
m_polling = false;
effects->stopMousePolling();
}
if (m_zoom == m_targetZoom) {
effects->makeOpenGLContextCurrent();
m_fbo.reset();
@ -243,10 +234,6 @@ void MagnifierEffect::toggle()
if (m_targetZoom == 1.0) {
m_targetZoom = 2;
}
if (!m_polling) {
m_polling = true;
effects->startMousePolling();
}
if (effects->isOpenGLCompositing() && !m_texture) {
effects->makeOpenGLContextCurrent();
m_texture = GLTexture::allocate(GL_RGBA16F, m_magnifierSize);
@ -258,10 +245,6 @@ void MagnifierEffect::toggle()
}
} else {
m_targetZoom = 1;
if (m_polling) {
m_polling = false;
effects->stopMousePolling();
}
}
effects->addRepaint(magnifierArea().adjusted(-FRAME_WIDTH, -FRAME_WIDTH, FRAME_WIDTH, FRAME_WIDTH));
}

View file

@ -50,7 +50,6 @@ private:
QRect magnifierArea(QPointF pos = cursorPos()) const;
double m_zoom;
double m_targetZoom;
bool m_polling; // Mouse polling
std::chrono::milliseconds m_lastPresentTime;
QSize m_magnifierSize;
std::unique_ptr<GLTexture> m_texture;

View file

@ -49,9 +49,6 @@ MouseClickEffect::MouseClickEffect()
MouseClickEffect::~MouseClickEffect()
{
if (m_enabled) {
effects->stopMousePolling();
}
}
void MouseClickEffect::reconfigure(ReconfigureFlags)
@ -234,10 +231,8 @@ void MouseClickEffect::toggleEnabled()
if (m_enabled) {
connect(effects, &EffectsHandler::mouseChanged, this, &MouseClickEffect::slotMouseChanged);
effects->startMousePolling();
} else {
disconnect(effects, &EffectsHandler::mouseChanged, this, &MouseClickEffect::slotMouseChanged);
effects->stopMousePolling();
}
m_clicks.clear();

View file

@ -55,12 +55,10 @@ MouseMarkEffect::MouseMarkEffect()
connect(effects, &EffectsHandler::screenLockingChanged, this, &MouseMarkEffect::screenLockingChanged);
reconfigure(ReconfigureAll);
arrow_tail = nullPoint();
effects->startMousePolling(); // We require it to detect activation as well
}
MouseMarkEffect::~MouseMarkEffect()
{
effects->stopMousePolling();
}
static int width_2 = 1;
@ -174,6 +172,9 @@ void MouseMarkEffect::slotMouseChanged(const QPointF &pos, const QPointF &,
Qt::MouseButtons, Qt::MouseButtons,
Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers)
{
if (effects->isScreenLocked()) {
return;
}
qCDebug(KWIN_MOUSEMARK) << "MouseChanged" << pos;
if (modifiers == m_arrowdraw_modifiers && m_arrowdraw_modifiers != Qt::NoModifier) { // start/finish arrow
if (arrow_tail != nullPoint()) {
@ -257,12 +258,6 @@ void MouseMarkEffect::screenLockingChanged(bool locked)
if (!marks.isEmpty() || !drawing.isEmpty()) {
effects->addRepaintFull();
}
// disable mouse polling while screen is locked.
if (locked) {
effects->stopMousePolling();
} else {
effects->startMousePolling();
}
}
bool MouseMarkEffect::isActive() const

View file

@ -110,7 +110,6 @@ StartupFeedbackEffect::StartupFeedbackEffect()
connect(effects, &EffectsHandler::startupRemoved, this, &StartupFeedbackEffect::gotRemoveStartup);
connect(effects, &EffectsHandler::startupChanged, this, &StartupFeedbackEffect::gotStartupChange);
connect(effects, &EffectsHandler::mouseChanged, this, &StartupFeedbackEffect::slotMouseChanged);
connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this, [this]() {
reconfigure(ReconfigureAll);
});
@ -130,9 +129,6 @@ StartupFeedbackEffect::StartupFeedbackEffect()
StartupFeedbackEffect::~StartupFeedbackEffect()
{
if (m_active) {
effects->stopMousePolling();
}
}
bool StartupFeedbackEffect::supported()
@ -320,9 +316,8 @@ void StartupFeedbackEffect::start(const Startup &startup)
if (!output) {
return;
}
if (!m_active) {
effects->startMousePolling();
connect(effects, &EffectsHandler::mouseChanged, this, &StartupFeedbackEffect::slotMouseChanged);
}
m_active = true;
@ -347,9 +342,10 @@ void StartupFeedbackEffect::start(const Startup &startup)
void StartupFeedbackEffect::stop()
{
if (m_active) {
effects->stopMousePolling();
if (!m_active) {
return;
}
disconnect(effects, &EffectsHandler::mouseChanged, this, &StartupFeedbackEffect::slotMouseChanged);
m_active = false;
m_lastPresentTime = std::chrono::milliseconds::zero();
effects->makeOpenGLContextCurrent();
@ -396,8 +392,7 @@ void StartupFeedbackEffect::prepareTextures(const QPixmap &pix, qreal devicePixe
break;
default:
// for safety
m_active = false;
m_lastPresentTime = std::chrono::milliseconds::zero();
stop();
break;
}
}

View file

@ -73,19 +73,16 @@ TrackMouseEffect::TrackMouseEffect()
KGlobalAccel::self()->setShortcut(action, QList<QKeySequence>());
connect(action, &QAction::triggered, this, &TrackMouseEffect::toggle);
connect(effects, &EffectsHandler::mouseChanged, this, &TrackMouseEffect::slotMouseChanged);
reconfigure(ReconfigureAll);
}
TrackMouseEffect::~TrackMouseEffect()
{
if (m_mousePolling) {
effects->stopMousePolling();
}
}
void TrackMouseEffect::reconfigure(ReconfigureFlags)
{
const bool active = bool(m_modifiers);
m_modifiers = Qt::KeyboardModifiers();
TrackMouseConfig::self()->read();
if (TrackMouseConfig::shift()) {
@ -100,15 +97,11 @@ void TrackMouseEffect::reconfigure(ReconfigureFlags)
if (TrackMouseConfig::meta()) {
m_modifiers |= Qt::MetaModifier;
}
if (m_modifiers) {
if (!m_mousePolling) {
effects->startMousePolling();
}
m_mousePolling = true;
} else if (m_mousePolling) {
effects->stopMousePolling();
m_mousePolling = false;
const bool newActive = bool(m_modifiers);
if (newActive && !active) {
connect(effects, &EffectsHandler::mouseChanged, this, &TrackMouseEffect::slotMouseChanged);
} else if (!newActive && active) {
disconnect(effects, &EffectsHandler::mouseChanged, this, &TrackMouseEffect::slotMouseChanged);
}
}
@ -155,10 +148,6 @@ void TrackMouseEffect::slotMouseChanged(const QPointF &, const QPointF &,
Qt::MouseButtons, Qt::MouseButtons,
Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers)
{
if (!m_mousePolling) { // we didn't ask for it but maybe someone else did...
return;
}
switch (m_state) {
case State::ActivatedByModifiers:
if (modifiers != m_modifiers) {

View file

@ -37,7 +37,6 @@ class TrackMouseEffect : public Effect
{
Q_OBJECT
Q_PROPERTY(Qt::KeyboardModifiers modifiers READ modifiers)
Q_PROPERTY(bool mousePolling READ isMousePolling)
public:
TrackMouseEffect();
~TrackMouseEffect() override;
@ -51,10 +50,6 @@ public:
{
return m_modifiers;
}
bool isMousePolling() const
{
return m_mousePolling;
}
private Q_SLOTS:
void toggle();
void slotMouseChanged(const QPointF &pos, const QPointF &old,
@ -68,7 +63,6 @@ private:
Inactive
};
State m_state = State::Inactive;
bool m_mousePolling = false;
float m_angle = 0;
Qt::KeyboardModifiers m_modifiers;
std::unique_ptr<RotatingArcsItem> m_rotatingArcsItem;

View file

@ -38,7 +38,6 @@ ZoomEffect::ZoomEffect()
: Effect()
, zoom(1)
, target_zoom(1)
, polling(false)
, zoomFactor(1.25)
, mouseTracking(MouseTrackingProportional)
, mousePointer(MousePointerScale)
@ -111,7 +110,6 @@ ZoomEffect::ZoomEffect()
timeline.setDuration(350);
timeline.setFrameRange(0, 100);
connect(&timeline, &QTimeLine::frameChanged, this, &ZoomEffect::timelineFrameChanged);
connect(effects, &EffectsHandler::mouseChanged, this, &ZoomEffect::slotMouseChanged);
connect(effects, &EffectsHandler::windowAdded, this, &ZoomEffect::slotWindowAdded);
connect(effects, &EffectsHandler::screenRemoved, this, &ZoomEffect::slotScreenRemoved);
@ -235,7 +233,7 @@ void ZoomEffect::reconfigure(ReconfigureFlags)
if (source_zoom < 0) {
// Load the saved zoom value.
source_zoom = 1.0;
target_zoom = ZoomConfig::initialZoom();
setTargetZoom(ZoomConfig::initialZoom());
if (target_zoom > 1.0) {
zoomIn(target_zoom);
}
@ -452,14 +450,9 @@ void ZoomEffect::zoomIn(double to)
{
source_zoom = zoom;
if (to < 0.0) {
target_zoom *= zoomFactor;
setTargetZoom(target_zoom * zoomFactor);
} else {
target_zoom = to;
}
target_zoom = std::min(target_zoom, 100.0);
if (!polling) {
polling = true;
effects->startMousePolling();
setTargetZoom(to);
}
cursorPoint = effects->cursorPos().toPoint();
if (mouseTracking == MouseTrackingDisabled) {
@ -471,13 +464,9 @@ void ZoomEffect::zoomIn(double to)
void ZoomEffect::zoomOut()
{
source_zoom = zoom;
target_zoom /= zoomFactor;
setTargetZoom(target_zoom / zoomFactor);
if ((zoomFactor > 1 && target_zoom < 1.01) || (zoomFactor < 1 && target_zoom > 0.99)) {
target_zoom = 1;
if (polling) {
polling = false;
effects->stopMousePolling();
}
setTargetZoom(1);
}
if (mouseTracking == MouseTrackingDisabled) {
prevPoint = effects->cursorPos().toPoint();
@ -488,11 +477,7 @@ void ZoomEffect::zoomOut()
void ZoomEffect::actualSize()
{
source_zoom = zoom;
target_zoom = 1;
if (polling) {
polling = false;
effects->stopMousePolling();
}
setTargetZoom(1);
effects->addRepaintFull();
}
@ -651,6 +636,19 @@ bool ZoomEffect::screenExistsAt(const QPoint &point) const
return output && output->geometry().contains(point);
}
void ZoomEffect::setTargetZoom(double value)
{
value = std::min(value, 100.0);
const bool newActive = value != 1.0;
const bool oldActive = target_zoom != 1.0;
if (newActive && !oldActive) {
connect(effects, &EffectsHandler::mouseChanged, this, &ZoomEffect::slotMouseChanged);
} else if (!newActive && oldActive) {
disconnect(effects, &EffectsHandler::mouseChanged, this, &ZoomEffect::slotMouseChanged);
}
target_zoom = value;
}
} // namespace
#include "moc_zoom.cpp"

View file

@ -82,6 +82,7 @@ private Q_SLOTS:
void slotWindowAdded(EffectWindow *w);
void slotWindowDamaged();
void slotScreenRemoved(Output *screen);
void setTargetZoom(double value);
private:
void showCursor();
@ -106,7 +107,6 @@ private:
double zoom;
double target_zoom;
double source_zoom;
bool polling; // Mouse polling
double zoomFactor;
enum MouseTrackingType {
MouseTrackingProportional = 0,